3proxy/src/plugins/FilePlugin/FilePlugin.c
2021-07-02 11:50:33 +03:00

917 lines
25 KiB
C

/*
(c) 2007-2021 by Vladimir Dubrovin <3proxy@3proxy.org>
please read License Agreement
*/
#include "../../structures.h"
#include "FilePlugin.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/timeb.h>
#include <fcntl.h>
#include <time.h>
#ifdef _WIN32
#ifndef _WINCE
#include <io.h>
#else
#include <sys/unistd.h>
#endif
#else
#include <unistd.h>
#ifndef O_BINARY
#define O_BINARY (0)
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef _WIN32
#define WINAPI
#define fp_size_t size_t
#else
#define fp_size_t int
#endif
static struct pluginlink * pl;
static pthread_mutex_t file_mutex;
unsigned long preview = 0;
char path[300];
static int counter = 0;
static int timeo = 0;
static char * fp_stringtable[] = {
/* 0 */ "HTTP/1.0 503 Service Unavailable\r\n"
"Proxy-Connection: close\r\n"
"Content-type: text/html; charset=us-ascii\r\n"
"\r\n"
"<html><head><title>503 Service Unavailable</title></head>\r\n"
"<body><h2>503 Service Unavailable</h2><h3>HTTP policy violation: you have no permission to perform this action. Please conatct helpdesk or Administrator.</h3></body></html>\r\n",
/* 1 */ "421 SMTP policy violation: you have no permission to perform this action. Please conatct helpdesk or Administrator.\r\n",
/* 2 */ "421 FTP policy violation: you have no permission to perform this action. Please conatct helpdesk or Administrator.\r\n",
NULL
};
enum states {
STATE_INITIAL = 0,
GOT_HTTP_REQUEST,
GOT_HTTP_CLI_HDR,
GOT_HTTP_SRV_HDR,
GOT_HTTP_CLI_HDR2,
GOT_HTTP_SRV_HDR2,
GOT_HTTP_CLIDATA,
GOT_HTTP_SRVDATA,
GOT_SMTP_REQ,
GOT_SMTP_DATA,
GOT_FTP_REQ,
GOT_FTP_CLIDATA,
GOT_FTP_SRVDATA,
FLUSH_DATA
};
struct fp_callback {
struct fp_callback *next;
FP_CALLBACK callback;
void * data;
int what;
int preview_size;
int max_size;
};
struct fp_stream {
struct fp_stream *next;
char * buf;
int state;
int what;
int needsrvconnect;
int preview_size;
long bufsize;
unsigned long clihdrwritten, clientwritten, clientsent, srvhdrwritten, serverwritten, serversent;
struct fp_callback *callbacks;
struct fp_filedata fpd;
} *fp_streams = NULL;
struct sockfuncs sso;
static void genpaths(struct fp_stream *fps){
if(fps->what & (FP_CLIDATA|FP_CLIHEADER)){
if(fps->fpd.path_cli) free(fps->fpd.path_cli);
fps->fpd.path_cli = malloc(strlen(path) + 10);
sprintf(fps->fpd.path_cli, path, counter++);
}
if(fps->what & (FP_SRVDATA|FP_SRVHEADER)){
if(fps->fpd.path_srv) free(fps->fpd.path_srv);
fps->fpd.path_srv = malloc(strlen(path) + 10);
sprintf(fps->fpd.path_srv, path, counter++);
}
}
static
#ifdef _WIN32
HANDLE
#else
int
#endif
initclientfile(struct fp_stream *fps){
fps->clientwritten = fps->clientsent = 0;
#ifdef _WIN32
if(fps->fpd.h_cli != INVALID_HANDLE_VALUE){
CloseHandle(fps->fpd.h_cli);
}
fps->fpd.h_cli = CreateFile(fps->fpd.path_cli, GENERIC_READ | GENERIC_WRITE, (fps->what & FP_SHAREFILE)? FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE:0, NULL, CREATE_ALWAYS, (fps->what & (FP_KEEPFILE|FP_SHAREFILE))? FILE_ATTRIBUTE_TEMPORARY : FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL);
return fps->fpd.h_cli;
#else
if(fps->fpd.fd_cli != -1) close(fps->fpd.fd_cli);
fps->fpd.fd_cli = open(fps->fpd.path_cli, O_BINARY|O_RDWR|O_CREAT|O_TRUNC, 0600);
return fps->fpd.fd_cli;
#endif
}
static
#ifdef _WIN32
HANDLE
#else
int
#endif
initserverfile(struct fp_stream *fps){
fps->serverwritten = fps->serversent = 0;
#ifdef _WIN32
if(fps->fpd.h_srv != INVALID_HANDLE_VALUE){
CloseHandle(fps->fpd.h_srv);
}
fps->fpd.h_srv = CreateFile(fps->fpd.path_srv, GENERIC_READ | GENERIC_WRITE, (fps->what & FP_SHAREFILE)? FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE:0, NULL, CREATE_ALWAYS, (fps->what & (FP_KEEPFILE|FP_SHAREFILE))? FILE_ATTRIBUTE_TEMPORARY : FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL);
return fps->fpd.h_srv;
#else
if(fps->fpd.fd_srv != -1) close(fps->fpd.fd_srv);
fps->fpd.fd_srv = open(fps->fpd.path_srv, O_BINARY|O_RDWR|O_CREAT|O_TRUNC, 0600);
return fps->fpd.fd_srv;
#endif
}
static void closefiles(struct fp_stream *fps){
#ifdef _WIN32
if(fps->fpd.h_cli != INVALID_HANDLE_VALUE) {
CloseHandle(fps->fpd.h_cli);
fps->fpd.h_cli = INVALID_HANDLE_VALUE;
if((fps->what & FP_SHAREFILE) && !(fps->what & FP_KEEPFILE)) DeleteFile(fps->fpd.path_cli);
}
if(fps->fpd.h_srv != INVALID_HANDLE_VALUE) {
CloseHandle(fps->fpd.h_srv);
fps->fpd.h_srv = INVALID_HANDLE_VALUE;
if((fps->what & FP_SHAREFILE) && !(fps->what & FP_KEEPFILE)) DeleteFile(fps->fpd.path_cli);
}
#else
if(fps->fpd.fd_cli != -1) {
close(fps->fpd.fd_cli);
fps->fpd.fd_cli = -1;
if(!(fps->what & FP_KEEPFILE)) unlink(fps->fpd.path_cli);
}
if(fps->fpd.fd_srv != -1) {
close(fps->fpd.fd_srv);
fps->fpd.fd_srv = -1;
if(!(fps->what & FP_KEEPFILE)) unlink(fps->fpd.path_srv);
}
#endif
if(fps->fpd.path_cli) {
free(fps->fpd.path_cli);
fps->fpd.path_cli = NULL;
}
if(fps->fpd.path_srv) {
free(fps->fpd.path_srv);
fps->fpd.path_srv = NULL;
}
fps->clihdrwritten = fps->clientwritten = fps->clientsent = fps->srvhdrwritten = fps->serverwritten = fps->serversent = 0;
}
static int searchsocket(SOCKET s, struct fp_stream **pfps){
struct fp_stream *fps = NULL;
int ret = 0;
pthread_mutex_lock(&file_mutex);
for(fps = fp_streams; fps; fps = fps->next){
if(fps->fpd.cp->clisock == s) {
ret = 1;
break;
}
if(fps->fpd.cp->remsock == s) {
ret = 2;
break;
}
if(fps->fpd.cp->ctrlsock == s) {
ret = 3;
break;
}
}
pthread_mutex_unlock(&file_mutex);
*pfps = fps;
return ret;
}
static void freecallback(struct fp_stream * fps, struct fp_callback * fpc){
if(fpc->next) freecallback(fps, fpc->next);
if(fpc->what & FP_CALLONREMOVE) (*fpc->callback)(FP_CALLONREMOVE, fpc->data, &fps->fpd, NULL, 0);
free(fpc);
}
static void removefps(struct fp_stream * fps){
if(!fp_streams) return;
pthread_mutex_lock(&file_mutex);
if(fp_streams == fps)fp_streams = fps->next;
else {
struct fp_stream *fps2;
for(fps2 = fp_streams; fps2->next; fps2 = fps2->next){
if(fps2->next == fps){
fps2->next = fps->next;
break;
}
}
}
pthread_mutex_unlock(&file_mutex);
if(fps->callbacks){
freecallback(fps, fps->callbacks);
fps->callbacks = 0;
}
closefiles(fps);
if(fps->buf) {
free(fps->buf);
fps->buf = NULL;
}
fps->state = 0;
}
static int WINAPI fp_connect(SOCKET s, const struct sockaddr *name, fp_size_t namelen){
return sso._connect(s, name, namelen);
}
void processcallbacks(struct fp_stream *fps, int what, char *msg, int size){
struct fp_callback *cb;
int state;
state = fps->state;
if(fps->what & what) {
fps->what = 0;
for(cb = fps->callbacks; cb; cb=cb->next){
if(cb->what & what){
cb->what = (*cb->callback)(what, cb->data, &(fps->fpd), msg, size);
}
fps->what |= cb->what;
}
}
if(fps->what & FP_REJECT){
switch(state){
/*
Fixme: handle different states
*/
case GOT_SMTP_REQ:
case GOT_SMTP_DATA:
fps->state = FLUSH_DATA;
pl->socksend(fps->fpd.cp->clisock, fp_stringtable[1], (int)strlen(fp_stringtable[1]), pl->conf->timeouts[STRING_S]);
fps->state = state;
break;
case GOT_HTTP_REQUEST:
case GOT_HTTP_CLI_HDR:
case GOT_HTTP_SRV_HDR:
case GOT_HTTP_CLI_HDR2:
case GOT_HTTP_SRV_HDR2:
case GOT_HTTP_CLIDATA:
case GOT_HTTP_SRVDATA:
if(!fps->serversent){
fps->state = FLUSH_DATA;
pl->socksend(fps->fpd.cp->clisock, fp_stringtable[0], (int)strlen(fp_stringtable[0]), pl->conf->timeouts[STRING_S]);
fps->state = state;
}
break;
case GOT_FTP_CLIDATA:
case GOT_FTP_REQ:
case GOT_FTP_SRVDATA:
fps->state = FLUSH_DATA;
pl->socksend(fps->fpd.cp->ctrlsock, fp_stringtable[1], (int)strlen(fp_stringtable[1]), pl->conf->timeouts[STRING_S]);
fps->state = state;
break;
default:
break;
}
if(fps->fpd.cp->remsock != INVALID_SOCKET)sso._closesocket(fps->fpd.cp->remsock);
fps->fpd.cp->remsock = INVALID_SOCKET;
if(fps->fpd.cp->clisock != INVALID_SOCKET)sso._closesocket(fps->fpd.cp->clisock);
fps->fpd.cp->clisock = INVALID_SOCKET;
}
}
static int copyfdtosock(struct fp_stream * fps, DIRECTION which, long len){
int res;
long toread;
int state;
#ifdef _WIN32
HANDLE h;
#else
int fd;
#endif
SOCKET sock;
long offset;
int sendchunk = 0;
state = fps->state;
fps->state = FLUSH_DATA;
if(!fps->buf){
fps->buf = malloc(2048);
if(!fps->buf) return -2;
fps->bufsize = 2048;
}
if(which == SERVER){
offset = fps->clientsent;
fps->clientsent += len;
#ifdef _WIN32
h = fps->fpd.h_cli;
#else
fd = fps->fpd.fd_cli;
#endif
sock = fps->fpd.cp->remsock;
}
else {
if(fps->fpd.cp->chunked){
if(fps->serversent < fps->srvhdrwritten && (fps->serversent + len) > fps->srvhdrwritten){
len -= fps->srvhdrwritten - fps->serversent;
if ((res = copyfdtosock(fps, which, fps->srvhdrwritten - fps->serversent))) return res;
}
if(fps->serversent >= fps->srvhdrwritten){
sprintf(fps->buf, "%lx\r\n", len);
sendchunk = (int)strlen(fps->buf);
if(pl->socksend(fps->fpd.cp->clisock, fps->buf, sendchunk, pl->conf->timeouts[STRING_S]) != sendchunk){
return -4;
}
}
}
offset = fps->serversent;
fps->serversent += len;
#ifdef _WIN32
h = fps->fpd.h_srv;
#else
fd = fps->fpd.fd_srv;
#endif
sock = fps->fpd.cp->clisock;
}
#ifdef _WIN32
if(SetFilePointer(h,offset,0,FILE_BEGIN)!=offset){
return -1;
}
#else
if(lseek(fd, offset, SEEK_SET) < 0) {
return -1;
}
#endif
while(len > 0){
/*
Fixme: prevent client/server timeouts
*/
toread = (len > fps->bufsize)? fps->bufsize:len;
#ifdef _WIN32
if(!ReadFile(h, fps->buf, (DWORD)toread,(DWORD *)&res,NULL)) {
#else
if((res = read(fd, fps->buf, toread)) <= 0) {
#endif
return -3;
}
if(pl->socksend(sock, fps->buf, res, pl->conf->timeouts[STRING_S]) != res) {
return -4;
}
len -= res;
}
if(sendchunk){
if(pl->socksend(sock, "\r\n", 2, pl->conf->timeouts[STRING_S]) != 2)
return -4;
}
fps->state = state;
return 0;
}
static int WINAPI fp_poll(struct pollfd *fds, unsigned int nfds, int timeout){
struct fp_stream *fps = NULL;
int res;
unsigned i;
int to;
for(i = 0; i<nfds; i++){
res = searchsocket(fds[i].fd, &fps);
if(res == 2 && fps->state == GOT_SMTP_DATA){
if(fds[i].events & POLLOUT){
fds[i].revents = POLLOUT;
return 1;
}
}
else if(res == 2 && (((fps->what & FP_CLIHEADER) && (fps->state == GOT_HTTP_REQUEST || fps->state == GOT_HTTP_CLI_HDR2)) || ((fps->what & FP_CLIDATA) && fps->state == GOT_HTTP_CLIDATA))){
if(fds[i].events & POLLIN){
processcallbacks(fps, (fps->state == GOT_HTTP_CLIDATA)?FP_CLIDATA:FP_CALLAFTERCLIHEADERS, NULL, 0);
if(fps->clihdrwritten + fps->clientwritten > fps->clientsent) {
if(copyfdtosock(fps, SERVER, (fps->clihdrwritten + fps->clientwritten) - fps->clientsent))
return -2;
}
if(fps->state) {
if(fps->what & FP_SRVHEADER) initserverfile(fps);
fps->state = GOT_HTTP_SRV_HDR;
}
}
else if(fds[i].events & POLLOUT){
fds[i].revents = POLLOUT;
return 1;
}
}
else if(res == 1 && (fps->state == GOT_HTTP_SRVDATA || fps->state == GOT_HTTP_SRV_HDR || fps->state == GOT_HTTP_SRV_HDR2)&& (fds[i].events & POLLIN)){
processcallbacks(fps, (fps->state == GOT_HTTP_SRVDATA)? FP_SRVDATA:FP_CALLAFTERSRVHEADERS, NULL, 0);
if(fps->srvhdrwritten + fps->serverwritten > fps->serversent) {
if(copyfdtosock(fps, CLIENT, (fps->srvhdrwritten + fps->serverwritten) - fps->serversent))
return -2;
}
closefiles(fps);
fps->state = 0;
}
}
return sso._poll(fds, nfds, timeout);
}
static int WINAPI fp_send(SOCKET s, const char *msg, fp_size_t len, int flags){
struct fp_stream *fps = NULL;
int res;
res = searchsocket(s, &fps);
if(res == 2){
if(fps->state == GOT_SMTP_DATA) {
if(fps->clihdrwritten + fps->clientwritten > fps->clientsent) {
processcallbacks(fps, FP_CLIDATA, NULL, 0);
if(copyfdtosock(fps, SERVER, (fps->clihdrwritten + fps->clientwritten) - fps->clientsent)) {
return -1;
}
fps->state = 0;
}
closefiles(fps);
fps->state = 0;
return sso._send(s, msg, len, flags);
}
if((((fps->what & FP_CLIHEADER) && (fps->state == GOT_HTTP_REQUEST || fps->state == GOT_HTTP_CLI_HDR2)) || ((fps->what & FP_CLIDATA) && fps->state == GOT_HTTP_CLIDATA))){
#ifdef _WIN32
if(SetFilePointer(fps->fpd.h_cli, fps->clientwritten + fps->clihdrwritten, 0, FILE_BEGIN) != (fps->clientwritten + fps->clihdrwritten)){
return -1;
}
if(!WriteFile(fps->fpd.h_cli, msg, (DWORD)len,(DWORD *)&res,NULL) || res != len){
return -1;
}
#else
if(lseek(fps->fpd.fd_cli, fps->clientwritten + fps->clihdrwritten, SEEK_SET) < 0) {
return -1;
}
if((res = write(fps->fpd.fd_cli, msg, len) != len)) return -1;
#endif
if(fps->state == GOT_HTTP_CLIDATA)fps->clientwritten += res;
else fps->clihdrwritten += res;
return res;
}
}
if(res == 1){
if(((fps->what & FP_SRVDATA) && (fps->state == GOT_HTTP_SRVDATA || fps->state == GOT_HTTP_SRV_HDR) && fps->fpd.cp->chunked && len < 16 )){
int hasnonzero = 0, i;
for(i=0; i < len; i++){
char c = msg[i];
if(c == '\r' || c == '\n') continue;
if((c<'0'|| c>'9') && (c<'A' || c>'F') && (c<'a' || c>'f')) {
return sso._send(s, msg, len, flags);
}
if(c != '0') hasnonzero = 1;
}
if(i>2 && !hasnonzero){
if(fps->srvhdrwritten + fps->serverwritten > fps->serversent) {
processcallbacks(fps, FP_SRVDATA, NULL, 0);
if(copyfdtosock(fps, CLIENT, (fps->srvhdrwritten + fps->serverwritten) - fps->serversent)) {
return -1;
}
fps->state = 0;
}
closefiles(fps);
fps->state = 0;
return sso._send(s, msg, len, flags);
}
return len;
}
if(((fps->what & FP_SRVHEADER) && (fps->state == GOT_HTTP_SRV_HDR || fps->state == GOT_HTTP_SRV_HDR2))){
#ifdef _WIN32
if(SetFilePointer(fps->fpd.h_srv, fps->serverwritten + fps->srvhdrwritten, 0, FILE_BEGIN) != (fps->serverwritten + fps->srvhdrwritten)){
return -1;
}
if(!WriteFile(fps->fpd.h_srv, msg, (DWORD)len,(DWORD *)&res,NULL) || res !=len){
return -1;
}
#else
if(lseek(fps->fpd.fd_srv, fps->serverwritten + fps->srvhdrwritten, SEEK_SET) < 0) {
return -1;
}
if((res = write(fps->fpd.fd_srv, msg, len) != len)) return -1;
#endif
fps->srvhdrwritten += res;
return res;
}
}
return sso._send(s, msg, len, flags);
}
static int WINAPI fp_sendto(SOCKET s, const void *msg, int len, int flags, const struct sockaddr *to, fp_size_t tolen){
struct fp_stream *fps = NULL;
int res;
res = searchsocket(s, &fps);
if(res == 2) {
switch(fps->state){
case GOT_SMTP_REQ:
if(!(fps->what & FP_CLIDATA)) break;
fps->state = GOT_SMTP_DATA;
initclientfile(fps);
case GOT_FTP_REQ:
if(fps->state == GOT_FTP_REQ){
if(!(fps->what & FP_CLIDATA)) break;
fps->state = GOT_FTP_CLIDATA;
initclientfile(fps);
}
case GOT_HTTP_CLI_HDR2:
if(fps->state == GOT_HTTP_CLI_HDR2){
processcallbacks(fps, FP_CALLAFTERCLIHEADERS, NULL, 0);
if ((fps->what & FP_REJECT)) return -1;
if((fps->what & FP_CLIDATA) && !(fps->what & FP_CLIHEADER)) initclientfile(fps);
else if(!(fps->what & FP_CLIDATA) && (fps->what & FP_CLIHEADER)){
if(fps->clihdrwritten + fps->clientwritten > fps->clientsent) {
if(copyfdtosock(fps, SERVER, (fps->clihdrwritten + fps->clientwritten) - fps->clientsent))
return -2;
}
}
fps->state = GOT_HTTP_CLIDATA;
}
case GOT_HTTP_REQUEST:
if(fps->state == GOT_HTTP_REQUEST && !(fps->what & FP_CLIHEADER)) break;
case GOT_SMTP_DATA:
case GOT_FTP_CLIDATA:
case GOT_FTP_SRVDATA:
case GOT_HTTP_CLIDATA:
if(!(fps->what & FP_CLIDATA)) break;
#ifdef _WIN32
if(SetFilePointer(fps->fpd.h_cli, fps->clientwritten + fps->clihdrwritten, 0, FILE_BEGIN) != (fps->clientwritten + fps->clihdrwritten)){
return -1;
}
if(!WriteFile(fps->fpd.h_cli, msg, (DWORD)len,(DWORD *)&res,NULL) || res != len) {
return -1;
}
#else
if(lseek(fps->fpd.fd_cli, fps->clientwritten + fps->clihdrwritten, SEEK_SET) < 0) {
return -1;
}
if((res = write(fps->fpd.fd_cli, msg, len) != len)) return -1;
#endif
if(fps->state == GOT_HTTP_REQUEST)fps->clihdrwritten += res;
else fps->clientwritten += res;
if(fps->preview_size && ((fps->clihdrwritten + fps->clientwritten) > (fps->clientsent + fps->preview_size))){
if(!fps->clientsent){
processcallbacks(fps, FP_PREVIEWCLI, NULL, 0);
if ((fps->what & FP_REJECT)) return -1;
}
if(copyfdtosock(fps, SERVER, (fps->clihdrwritten + fps->clientwritten) - (fps->clientsent + fps->preview_size)))
return -1;
}
return res;
}
}
else if(res == 1){
switch(fps->state){
case GOT_HTTP_SRV_HDR2:
processcallbacks(fps, FP_CALLAFTERSRVHEADERS, NULL, 0);
if ((fps->what & FP_REJECT)) return REJECT;
if((fps->what & FP_SRVDATA) && !(fps->what & FP_SRVHEADER)) initserverfile(fps);
else if(!(fps->what & FP_SRVDATA) && (fps->what & FP_SRVHEADER)){
if(fps->srvhdrwritten + fps->serverwritten > fps->serversent) {
if(copyfdtosock(fps, CLIENT, (fps->srvhdrwritten + fps->serverwritten) - fps->serversent))
return -2;
}
}
fps->state = GOT_HTTP_SRVDATA;
case GOT_FTP_REQ:
if(fps->state == GOT_FTP_REQ){
if(!(fps->what & FP_SRVDATA)) break;
fps->state = GOT_FTP_SRVDATA;
initserverfile(fps);
}
case GOT_HTTP_SRV_HDR:
if(fps->state == GOT_HTTP_SRV_HDR && !(fps->what & FP_SRVHEADER)) break;
case GOT_HTTP_SRVDATA:
case GOT_FTP_SRVDATA:
case GOT_FTP_CLIDATA:
if(!(fps->what & FP_SRVDATA)) break;
#ifdef _WIN32
if(SetFilePointer(fps->fpd.h_srv, fps->serverwritten + fps->srvhdrwritten, 0, FILE_BEGIN) != (fps->serverwritten + fps->srvhdrwritten)){
return -1;
}
if(!WriteFile(fps->fpd.h_srv, msg, (DWORD)len,(DWORD *)&res,NULL) || res != len){
return -1;
}
#else
if(lseek(fps->fpd.fd_srv, fps->serverwritten + fps->srvhdrwritten, SEEK_SET) < 0) {
return -1;
}
if((res = write(fps->fpd.fd_srv, msg, len) != len)) return -1;
#endif
if(fps->state == GOT_HTTP_SRV_HDR)fps->srvhdrwritten += res;
else fps->serverwritten += res;
if(fps->preview_size && ((fps->srvhdrwritten + fps->serverwritten) > (fps->serversent + fps->preview_size))){
if(!fps->serversent){
processcallbacks(fps, FP_PREVIEWSRV, NULL, 0);
if ((fps->what & FP_REJECT)) return -1;
}
if(copyfdtosock(fps, CLIENT, (fps->srvhdrwritten + fps->serverwritten) - (fps->serversent + fps->preview_size)))
return -1;
}
return res;
}
}
return sso._sendto(s, msg, len, flags, to, tolen);
}
static int WINAPI fp_recv(SOCKET s, void *buf, fp_size_t len, int flags){
return sso._recv(s, buf, len, flags);
}
static int WINAPI fp_recvfrom(SOCKET s, void * buf, fp_size_t len, int flags, struct sockaddr * from, fp_size_t * fromlen){
return sso._recvfrom(s, buf, len, flags, from, fromlen);
}
static int WINAPI fp_shutdown(SOCKET s, int how){
struct fp_stream *fps = NULL;
int res;
res = searchsocket(s, &fps);
if(res){
if(fps->state == GOT_HTTP_SRV_HDR || fps->state == GOT_HTTP_SRVDATA || fps->state == GOT_FTP_SRVDATA){
if(fps->srvhdrwritten + fps->serverwritten > fps->serversent) {
processcallbacks(fps, FP_SRVDATA, NULL, 0);
copyfdtosock(fps, CLIENT, (fps->srvhdrwritten + fps->serverwritten) - fps->serversent);
}
closefiles(fps);
fps->state = 0;
}
else if(fps->state == GOT_FTP_CLIDATA){
if(fps->clihdrwritten + fps->clientwritten > fps->clientsent) {
processcallbacks(fps, FP_CLIDATA, NULL, 0);
copyfdtosock(fps, SERVER, (fps->clihdrwritten + fps->clientwritten) - fps->clientsent);
}
closefiles(fps);
fps->state = 0;
}
}
return sso._shutdown(s, how);
}
static int WINAPI fp_closesocket(SOCKET s){
return sso._closesocket(s);
}
struct fp_stream * addfps(struct clientparam *cp){
struct fp_stream *fps;
for(fps = fp_streams; fps && fps->fpd.cp != cp; fps = fps->next);
if(!fps) {
fps = malloc(sizeof(struct fp_stream));
if(!fps){
return NULL;
}
memset(fps, 0, sizeof(struct fp_stream));
fps->fpd.cp = cp;
fps->next = fp_streams;
fp_streams = fps;
#ifdef _WIN32
fps->fpd.h_cli = fps->fpd.h_srv = INVALID_HANDLE_VALUE;
#else
fps->fpd.fd_cli = fps->fpd.fd_srv = -1;
#endif
}
return fps;
}
static int fp_registercallback (int what, int max_size, int preview_size, struct clientparam *cp, FP_CALLBACK cb, void *data){
struct fp_callback * fpc;
struct fp_stream *fps;
fpc = malloc(sizeof(struct fp_callback));
if(!fpc) return 0;
fpc->what = what;
fpc->preview_size = preview_size;
fpc->max_size = max_size;
fpc->data = data;
fpc->callback = cb;
pthread_mutex_lock(&file_mutex);
fps = addfps(cp);
if(fps){
fpc->next = fps->callbacks;
fps->callbacks = fpc;
fps->what |= fpc->what;
if(preview_size > fps->preview_size) fps->preview_size = preview_size;
}
else free(fpc);
pthread_mutex_unlock(&file_mutex);
return fps?1:0;
}
static void * fp_open(void * idata, struct srvparam * param){
return idata;
}
#define FC ((struct fp_stream *)fc)
static FILTER_ACTION fp_client(void *fo, struct clientparam * param, void** fc){
pthread_mutex_lock(&file_mutex);
(*fc) = (void *)addfps(param);
pthread_mutex_unlock(&file_mutex);
return CONTINUE;
}
static FILTER_ACTION fp_request(void *fc, struct clientparam * param, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p){
if(fc && (param->service == S_PROXY)){
if(FC->state) {
closefiles(FC);
FC->state = 0;
}
processcallbacks(FC, FP_CALLONREQUEST, *buf_p + offset, *length_p - offset);
if(FC->what &FP_REJECT) return REJECT;
FC->state = GOT_HTTP_REQUEST;
genpaths(FC);
if(FC->what & FP_CLIHEADER) initclientfile(FC);
}
return CONTINUE;
}
static FILTER_ACTION fp_hcli(void *fc, struct clientparam * param, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p){
if(fc && param->service == S_SMTPP) {
processcallbacks(FC, FP_CALLONREQUEST, *buf_p + offset, *length_p - offset);
if(FC->what & FP_REJECT) return REJECT;
if(!FC->state)genpaths(FC);
FC->state = GOT_SMTP_REQ;
}
if(fc && param->service == S_FTPPR) {
processcallbacks(FC, FP_CALLONREQUEST, *buf_p + offset, *length_p - offset);
if(FC->what & FP_REJECT) return REJECT;
genpaths(FC);
FC->state = GOT_FTP_REQ;
}
return CONTINUE;
}
static FILTER_ACTION fp_hsrv(void *fc, struct clientparam * param, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p){
if(fc && param->service == S_PROXY && (FC->state == GOT_HTTP_REQUEST || FC->state == GOT_HTTP_CLI_HDR || FC->state == GOT_HTTP_CLIDATA)){
if(FC->what & FP_SRVHEADER) initserverfile(FC);
FC->state = GOT_HTTP_SRV_HDR;
}
return CONTINUE;
}
static FILTER_ACTION fp_dcli(void *fc, struct clientparam * param, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p){
if(fc && FC->state == GOT_HTTP_REQUEST){
FC->state = GOT_HTTP_CLI_HDR2;
}
return CONTINUE;
}
static FILTER_ACTION fp_dsrv(void *fc, struct clientparam * param, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p){
if(fc && (FC->state == GOT_HTTP_REQUEST || FC->state == GOT_HTTP_CLI_HDR || FC->state == GOT_HTTP_CLIDATA || FC->state == GOT_HTTP_CLIDATA || FC->state == GOT_HTTP_SRV_HDR)){
FC->state = GOT_HTTP_SRV_HDR2;
}
return CONTINUE;
}
static void fp_clear(void *fc){
removefps(FC);
free(fc);
}
static void fp_close(void *fo){
}
static struct filter fp_filter = {
NULL,
"filefilter",
"filefilter",
fp_open,
fp_client,
fp_request,
fp_hcli,
fp_hsrv,
NULL,
fp_dcli,
fp_dsrv,
fp_clear,
fp_close,
};
static struct symbol fp_symbols[] = {
{fp_symbols + 1, "fp_registercallback", (void*) fp_registercallback},
{NULL, "fp_stringtable", (void*) fp_stringtable}
};
static int h_cachedir(int argc, unsigned char **argv){
char * dirp;
size_t len;
dirp = (argc > 1)? argv[1] : getenv("TEMP");
len = strlen(dirp);
if(!dirp || !len || len > 200 || strchr(dirp, '%')) {
fprintf(stderr, "FilePlugin: invalid directory path: %s\n", dirp);
return (1);
}
#ifdef _WIN32
if(dirp[len-1] == '\\') dirp[len-1] = 0;
sprintf(path, "%.256s\\%%07d.tmp", dirp);
#else
if(dirp[len-1] == '/') dirp[len-1] = 0;
sprintf(path, "%.256s/%%07d.tmp", dirp);
#endif
return 0;
}
static int h_preview(int argc, unsigned char **argv){
preview = atoi(argv[1]);
return 0;
}
static struct commands file_commandhandlers[] = {
{file_commandhandlers + 1, "file_cachedir", h_cachedir, 2, 2},
{NULL, "file_preview", h_preview, 2, 2},
};
static int file_loaded=0;
#ifdef WATCOM
#pragma aux file_plugin "*" parm caller [ ] value struct float struct routine [eax] modify [eax ecx edx]
#undef PLUGINCALL
#define PLUGINCALL
#endif
PLUGINAPI int PLUGINCALL file_plugin (struct pluginlink * pluginlink,
int argc, char** argv){
if(!file_loaded){
pthread_mutex_init(&file_mutex, NULL);
file_loaded = 1;
pl = pluginlink;
memcpy(&sso, pl->so, sizeof(struct sockfuncs));
pl->so->_poll = fp_poll;
pl->so->_send = fp_send;
pl->so->_sendto = fp_sendto;
pl->so->_recv = fp_recv;
pl->so->_recvfrom = fp_recvfrom;
pl->so->_shutdown = fp_shutdown;
pl->so->_closesocket = fp_closesocket;
fp_filter.next = pl->conf->filters;
pl->conf->filters = &fp_filter;
fp_symbols[1].next = pl->symbols.next;
pl->symbols.next = fp_symbols;
file_commandhandlers[1].next = pl->commandhandlers->next;
pl->commandhandlers->next = file_commandhandlers;
}
h_cachedir(0, NULL);
preview = 32768;
return 0;
}
#ifdef __cplusplus
}
#endif