X-Git-Url: https://code.citadel.org/?p=citadel.git;a=blobdiff_plain;f=citadel%2Ffile_ops.c;h=9040c4c746b4d009ba5cad19ebc91644be48c1b3;hp=9d99dbfaf041d032b907145acfda92efea8597fe;hb=da1debddf5988512ac50ff0b62ac85c8f3b8d0f4;hpb=54b54a07b29cd57a19728f468e19cf887cda3873 diff --git a/citadel/file_ops.c b/citadel/file_ops.c index 9d99dbfaf..9040c4c74 100644 --- a/citadel/file_ops.c +++ b/citadel/file_ops.c @@ -1,51 +1,146 @@ +/* + * Server functions which handle file transfers and room directories. + */ + +#include "sysdep.h" #include #include #include #include #include #include +#include #include #include -#include -#include +#include + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include +#include #include "citadel.h" #include "server.h" -#include "proto.h" +#include "config.h" +#include "file_ops.h" +#include "sysdep_decls.h" +#include "support.h" +#include "room_ops.h" +#include "msgbase.h" +#include "citserver.h" +#include "threads.h" + +#ifndef HAVE_SNPRINTF +#include "snprintf.h" +#endif + +#include "ctdl_module.h" +#include "user_ops.h" + +/* + * network_talking_to() -- concurrency checker + */ +static HashList *nttlist = NULL; +int network_talking_to(const char *nodename, long len, int operation) { + + int retval = 0; + HashPos *Pos = NULL; + void *vdata; + + begin_critical_section(S_NTTLIST); + + switch(operation) { + + case NTT_ADD: + if (nttlist == NULL) + nttlist = NewHash(1, NULL); + Put(nttlist, nodename, len, NewStrBufPlain(nodename, len), HFreeStrBuf); + syslog(LOG_DEBUG, "nttlist: added <%s>\n", nodename); + break; + case NTT_REMOVE: + if ((nttlist == NULL) || + (GetCount(nttlist) == 0)) + break; + Pos = GetNewHashPos(nttlist, 1); + GetHashPosFromKey (nttlist, nodename, len, Pos); + + DeleteEntryFromHash(nttlist, Pos); + DeleteHashPos(&Pos); + syslog(LOG_DEBUG, "nttlist: removed <%s>\n", nodename); + + break; + + case NTT_CHECK: + if ((nttlist == NULL) || + (GetCount(nttlist) == 0)) + break; + if (!GetHash(nttlist, nodename, len, &vdata)) + retval ++; + syslog(LOG_DEBUG, "nttlist: have [%d] <%s>\n", retval, nodename); + break; + } + + end_critical_section(S_NTTLIST); + return(retval); +} +void cleanup_nttlist(void) +{ + begin_critical_section(S_NTTLIST); + DeleteHash(&nttlist); + end_critical_section(S_NTTLIST); +} + + + +/* + * Server command to delete a file from a room's directory + */ void cmd_delf(char *filename) { char pathname[64]; int a; - if (!(CC->logged_in)) { - cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN); - return; - } - - if (!is_room_aide()) { - cprintf("%d Higher access required.\n", - ERROR+HIGHER_ACCESS_REQUIRED); + if (CtdlAccessCheck(ac_room_aide)) return; - } - - if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) { - cprintf("%d No directory in this room.\n",ERROR+NOT_HERE); + if ((CC->room.QRflags & QR_DIRECTORY) == 0) { + cprintf("%d No directory in this room.\n", + ERROR + NOT_HERE); return; - } + } - if (strlen(filename)==0) { + if (IsEmptyStr(filename)) { cprintf("%d You must specify a file name.\n", - ERROR+FILE_NOT_FOUND); + ERROR + FILE_NOT_FOUND); return; + } + for (a = 0; !IsEmptyStr(&filename[a]); ++a) { + if ( (filename[a] == '/') || (filename[a] == '\\') ) { + filename[a] = '_'; } - for (a=0; aquickroom.QRdirname,filename); - a=unlink(pathname); - if (a==0) cprintf("%d File '%s' deleted.\n",OK,pathname); - else cprintf("%d File '%s' not found.\n",ERROR+FILE_NOT_FOUND,pathname); } + snprintf(pathname, sizeof pathname, + "%s/%s/%s", + ctdl_file_dir, + CC->room.QRdirname, filename); + a = unlink(pathname); + if (a == 0) { + cprintf("%d File '%s' deleted.\n", CIT_OK, pathname); + } + else { + cprintf("%d File '%s' not found.\n", + ERROR + FILE_NOT_FOUND, pathname); + } +} @@ -55,177 +150,93 @@ void cmd_delf(char *filename) */ void cmd_movf(char *cmdbuf) { - char filename[256]; - char pathname[256]; - char newpath[256]; - char newroom[256]; - char buf[256]; - FILE *fp; + char filename[PATH_MAX]; + char pathname[PATH_MAX]; + char newpath[PATH_MAX]; + char newroom[ROOMNAMELEN]; + char buf[PATH_MAX]; int a; - int target_room = (-1); - struct quickroom qrbuf; + struct ctdlroom qrbuf; + int rv = 0; - extract(filename,cmdbuf,0); - extract(newroom,cmdbuf,1); + extract_token(filename, cmdbuf, 0, '|', sizeof filename); + extract_token(newroom, cmdbuf, 1, '|', sizeof newroom); - if (!(CC->logged_in)) { - cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN); - return; - } - - if (!is_room_aide()) { - cprintf("%d Higher access required.\n", - ERROR+HIGHER_ACCESS_REQUIRED); - return; - } + if (CtdlAccessCheck(ac_room_aide)) return; - if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) { - cprintf("%d No directory in this room.\n",ERROR+NOT_HERE); + if ((CC->room.QRflags & QR_DIRECTORY) == 0) { + cprintf("%d No directory in this room.\n", + ERROR + NOT_HERE); return; - } + } - if (strlen(filename)==0) { + if (IsEmptyStr(filename)) { cprintf("%d You must specify a file name.\n", - ERROR+FILE_NOT_FOUND); + ERROR + FILE_NOT_FOUND); return; - } + } - for (a=0; aquickroom.QRdirname,filename); - if (access(pathname,0)!=0) { + for (a = 0; !IsEmptyStr(&filename[a]); ++a) { + if ( (filename[a] == '/') || (filename[a] == '\\') ) { + filename[a] = '_'; + } + } + snprintf(pathname, sizeof pathname, "./files/%s/%s", + CC->room.QRdirname, filename); + if (access(pathname, 0) != 0) { cprintf("%d File '%s' not found.\n", - ERROR+FILE_NOT_FOUND,pathname); + ERROR + FILE_NOT_FOUND, pathname); return; - } + } - for (a=0; a>./files/%s/filedir", - CC->quickroom.QRdirname, - filename, - qrbuf.QRdirname); - system(buf); - cprintf("%d File '%s' has been moved.\n",OK,filename); - } + snprintf(buf, sizeof buf, + "cat ./files/%s/filedir |grep \"%s\" >>./files/%s/filedir", + CC->room.QRdirname, filename, qrbuf.QRdirname); + rv = system(buf); + cprintf("%d File '%s' has been moved.\n", CIT_OK, filename); +} /* - * send a file over the net - */ -void cmd_netf(char *cmdbuf) -{ - char pathname[256],filename[256],destsys[256],buf[256],outfile[256]; - int a,e; - long now; - FILE *ofp; - - extract(filename,cmdbuf,0); - extract(destsys,cmdbuf,1); - - if (!(CC->logged_in)) { - cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN); - return; - } - - if (!is_room_aide()) { - cprintf("%d Higher access required.\n", - ERROR+HIGHER_ACCESS_REQUIRED); - return; - } - - if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) { - cprintf("%d No directory in this room.\n",ERROR+NOT_HERE); - return; - } - - if (strlen(filename)==0) { - cprintf("%d You must specify a file name.\n", - ERROR+FILE_NOT_FOUND); - return; - } - - for (a=0; aquickroom.QRdirname,filename); - if (access(pathname,0)!=0) { - cprintf("%d File '%s' not found.\n", - ERROR+FILE_NOT_FOUND,pathname); - return; - } - sprintf(buf,"sysop@%s",destsys); - e=alias(buf); - if (e!=M_BINARY) { - cprintf("%d No such system: '%s'\n", - ERROR+NO_SUCH_SYSTEM,destsys); - return; - } - sprintf(outfile,"%s/network/spoolin/nsf.%d",BBSDIR,getpid()); - ofp=fopen(outfile,"a"); - if (ofp==NULL) { - cprintf("%d internal error\n",ERROR); - return; - } - - putc(255,ofp); - putc(MES_NORMAL,ofp); - putc(0,ofp); - fprintf(ofp,"Pcit%ld",CC->usersupp.usernum); putc(0,ofp); - time(&now); - fprintf(ofp,"T%ld",now); putc(0,ofp); - fprintf(ofp,"A%s",CC->usersupp.fullname); putc(0,ofp); - fprintf(ofp,"O%s",CC->quickroom.QRname); putc(0,ofp); - fprintf(ofp,"N%s",NODENAME); putc(0,ofp); - fprintf(ofp,"D%s",destsys); putc(0,ofp); - fprintf(ofp,"SFILE"); putc(0,ofp); - putc('M',ofp); - fclose(ofp); - - sprintf(buf,"cd ./files/%s; uuencode %s <%s 2>/dev/null >>%s", - CC->quickroom.QRdirname,filename,filename,outfile); - system(buf); - - ofp = fopen(outfile,"a"); - putc(0,ofp); - fclose(ofp); - - cprintf("%d File '%s' has been sent to %s.\n",OK,filename,destsys); - system("nohup ./netproc >/dev/null 2>&1 &"); - return; - } - -/* - * This code is common to all commands which open a file for downloading. + * This code is common to all commands which open a file for downloading, + * regardless of whether it's a file from the directory, an image, a network + * spool file, a MIME attachment, etc. * It examines the file and displays the OK result code and some information * about the file. NOTE: this stuff is Unix dependent. */ -void OpenCmdResult() { +void OpenCmdResult(char *filename, const char *mime_type) +{ struct stat statbuf; + time_t modtime; + long filesize; fstat(fileno(CC->download_fp), &statbuf); - cprintf("%d %ld|%ld\n", OK, statbuf.st_size, statbuf.st_mtime); - } + CC->download_fp_total = statbuf.st_size; + filesize = (long) statbuf.st_size; + modtime = (time_t) statbuf.st_mtime; + + cprintf("%d %ld|%ld|%s|%s\n", + CIT_OK, filesize, (long)modtime, filename, mime_type); +} /* @@ -234,105 +245,132 @@ void OpenCmdResult() { void cmd_open(char *cmdbuf) { char filename[256]; - char pathname[256]; + char pathname[PATH_MAX]; int a; - extract(filename,cmdbuf,0); + extract_token(filename, cmdbuf, 0, '|', sizeof filename); - if (!(CC->logged_in)) { - cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN); - return; - } + if (CtdlAccessCheck(ac_logged_in)) return; - if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) { - cprintf("%d No directory in this room.\n",ERROR+NOT_HERE); + if ((CC->room.QRflags & QR_DIRECTORY) == 0) { + cprintf("%d No directory in this room.\n", + ERROR + NOT_HERE); return; - } + } - if (strlen(filename)==0) { + if (IsEmptyStr(filename)) { cprintf("%d You must specify a file name.\n", - ERROR+FILE_NOT_FOUND); + ERROR + FILE_NOT_FOUND); return; - } + } if (CC->download_fp != NULL) { - cprintf("%d You already have a download file open.\n",ERROR); + cprintf("%d You already have a download file open.\n", + ERROR + RESOURCE_BUSY); return; - } + } - for (a=0; aquickroom.QRdirname,filename); - CC->download_fp = fopen(pathname,"r"); + snprintf(pathname, sizeof pathname, + "%s/%s/%s", + ctdl_file_dir, + CC->room.QRdirname, filename); + CC->download_fp = fopen(pathname, "r"); - if (CC->download_fp==NULL) { + if (CC->download_fp == NULL) { cprintf("%d cannot open %s: %s\n", - ERROR,pathname,strerror(errno)); + ERROR + INTERNAL_ERROR, pathname, strerror(errno)); return; - } - - OpenCmdResult(); } + OpenCmdResult(filename, "application/octet-stream"); +} + /* * open an image file */ void cmd_oimg(char *cmdbuf) { char filename[256]; - char pathname[256]; - struct usersupp usbuf; - char which_user[32]; + char pathname[PATH_MAX]; + char MimeTestBuf[32]; + struct ctdluser usbuf; + char which_user[USERNAME_SIZE]; int which_floor; int a; + int rv; - extract(filename,cmdbuf,0); + extract_token(filename, cmdbuf, 0, '|', sizeof filename); - if (strlen(filename)==0) { + if (IsEmptyStr(filename)) { cprintf("%d You must specify a file name.\n", - ERROR+FILE_NOT_FOUND); + ERROR + FILE_NOT_FOUND); return; - } + } if (CC->download_fp != NULL) { - cprintf("%d You already have a download file open.\n",ERROR); + cprintf("%d You already have a download file open.\n", + ERROR + RESOURCE_BUSY); return; - } + } - if (!strucmp(filename, "_userpic_")) { - extract(which_user, cmdbuf, 1); - if (getuser(&usbuf, which_user) != 0) { - cprintf("%d No such user.\n", ERROR+NO_SUCH_USER); + if (!strcasecmp(filename, "_userpic_")) { + extract_token(which_user, cmdbuf, 1, '|', sizeof which_user); + if (CtdlGetUser(&usbuf, which_user) != 0) { + cprintf("%d No such user.\n", + ERROR + NO_SUCH_USER); return; - } - sprintf(pathname, "./userpics/%ld.gif", usbuf.usernum); } - else if (!strucmp(filename, "_floorpic_")) { + snprintf(pathname, sizeof pathname, + "%s/%ld", + ctdl_usrpic_dir, + usbuf.usernum); + } else if (!strcasecmp(filename, "_floorpic_")) { which_floor = extract_int(cmdbuf, 1); - sprintf(pathname, "./images/floor.%d.gif", which_floor); - } - else if (!strucmp(filename, "_roompic_")) { - sprintf(pathname, "./images/room.%d.gif", CC->curr_rm); - } - else { - for (a=0; aroom, ctdl_image_dir); + } else { + for (a = 0; !IsEmptyStr(&filename[a]); ++a) { filename[a] = tolower(filename[a]); - if (filename[a]=='/') filename[a] = '_'; + if ( (filename[a] == '/') || (filename[a] == '\\') ) { + filename[a] = '_'; } - sprintf(pathname,"./images/%s.gif",filename); } - - CC->download_fp = fopen(pathname,"r"); + snprintf(pathname, sizeof pathname, + "%s/%s", + ctdl_image_dir, + filename); + } + + CC->download_fp = fopen(pathname, "rb"); + if (CC->download_fp == NULL) { + strcat(pathname, ".gif"); + CC->download_fp = fopen(pathname, "rb"); + } if (CC->download_fp == NULL) { cprintf("%d Cannot open %s: %s\n", - ERROR+FILE_NOT_FOUND,pathname,strerror(errno)); + ERROR + FILE_NOT_FOUND, pathname, strerror(errno)); + return; + } + rv = fread(&MimeTestBuf[0], 1, 32, CC->download_fp); + if (rv == -1) { + cprintf("%d Cannot access %s: %s\n", + ERROR + FILE_NOT_FOUND, pathname, strerror(errno)); return; - } - - OpenCmdResult(); } + rewind (CC->download_fp); + OpenCmdResult(pathname, GuessMimeType(&MimeTestBuf[0], 32)); +} + /* * open a file for uploading */ @@ -340,52 +378,61 @@ void cmd_uopn(char *cmdbuf) { int a; - extract(CC->upl_file,cmdbuf,0); - extract(CC->upl_comment,cmdbuf,1); + extract_token(CC->upl_file, cmdbuf, 0, '|', sizeof CC->upl_file); + extract_token(CC->upl_mimetype, cmdbuf, 1, '|', sizeof CC->upl_mimetype); + extract_token(CC->upl_comment, cmdbuf, 2, '|', sizeof CC->upl_comment); - if (!(CC->logged_in)) { - cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN); - return; - } + if (CtdlAccessCheck(ac_logged_in)) return; - if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) { - cprintf("%d No directory in this room.\n",ERROR+NOT_HERE); + if ((CC->room.QRflags & QR_DIRECTORY) == 0) { + cprintf("%d No directory in this room.\n", + ERROR + NOT_HERE); return; - } + } - if (strlen(CC->upl_file)==0) { + if (IsEmptyStr(CC->upl_file)) { cprintf("%d You must specify a file name.\n", - ERROR+FILE_NOT_FOUND); + ERROR + FILE_NOT_FOUND); return; - } + } if (CC->upload_fp != NULL) { - cprintf("%d You already have a upload file open.\n",ERROR); + cprintf("%d You already have a upload file open.\n", + ERROR + RESOURCE_BUSY); return; - } + } - for (a=0; aupl_file); ++a) - if (CC->upl_file[a]=='/') CC->upl_file[a] = '_'; - sprintf(CC->upl_path,"./files/%s/%s",CC->quickroom.QRdirname,CC->upl_file); - sprintf(CC->upl_filedir,"./files/%s/filedir",CC->quickroom.QRdirname); - - CC->upload_fp = fopen(CC->upl_path,"r"); + for (a = 0; !IsEmptyStr(&CC->upl_file[a]); ++a) { + if ( (CC->upl_file[a] == '/') || (CC->upl_file[a] == '\\') ) { + CC->upl_file[a] = '_'; + } + } + snprintf(CC->upl_path, sizeof CC->upl_path, + "%s/%s/%s", + ctdl_file_dir, + CC->room.QRdirname, CC->upl_file); + snprintf(CC->upl_filedir, sizeof CC->upl_filedir, + "%s/%s/filedir", + ctdl_file_dir, + CC->room.QRdirname); + + CC->upload_fp = fopen(CC->upl_path, "r"); if (CC->upload_fp != NULL) { fclose(CC->upload_fp); CC->upload_fp = NULL; cprintf("%d '%s' already exists\n", - ERROR+ALREADY_EXISTS,CC->upl_path); + ERROR + ALREADY_EXISTS, CC->upl_path); return; - } + } - CC->upload_fp = fopen(CC->upl_path,"wb"); + CC->upload_fp = fopen(CC->upl_path, "wb"); if (CC->upload_fp == NULL) { cprintf("%d Cannot open %s: %s\n", - ERROR,CC->upl_path,strerror(errno)); + ERROR + INTERNAL_ERROR, CC->upl_path, strerror(errno)); return; - } - cprintf("%d Ok\n",OK); } + cprintf("%d Ok\n", CIT_OK); +} @@ -400,99 +447,117 @@ void cmd_uimg(char *cmdbuf) int a; if (num_parms(cmdbuf) < 2) { - cprintf("%d Usage error.\n", ERROR); + cprintf("%d Usage error.\n", ERROR + ILLEGAL_VALUE); return; - } + } - is_this_for_real = extract_int(cmdbuf,0); - extract(basenm, cmdbuf, 1); + is_this_for_real = extract_int(cmdbuf, 0); + extract_token(CC->upl_mimetype, cmdbuf, 1, '|', sizeof CC->upl_mimetype); + extract_token(basenm, cmdbuf, 2, '|', sizeof basenm); if (CC->upload_fp != NULL) { - cprintf("%d You already have an upload file open.\n", ERROR); + cprintf("%d You already have an upload file open.\n", + ERROR + RESOURCE_BUSY); return; - } + } strcpy(CC->upl_path, ""); - for (a=0; ausersupp.axlevel >= 6) { - sprintf(CC->upl_path, "./images/%s", basenm); - } + if (CC->user.axlevel >= AxAideU) { + snprintf(CC->upl_path, sizeof CC->upl_path, + "%s/%s", + ctdl_image_dir, + basenm); + } - if (!strucmp(basenm, "_userpic_")) { - sprintf(CC->upl_path, "./userpics/%ld.gif", - CC->usersupp.usernum); - } + if (!strcasecmp(basenm, "_userpic_")) { + snprintf(CC->upl_path, sizeof CC->upl_path, + "%s/%ld.gif", + ctdl_usrpic_dir, + CC->user.usernum); + } - if ( (!strucmp(basenm, "_floorpic_")) && (CC->usersupp.axlevel >= 6) ) { + if ((!strcasecmp(basenm, "_floorpic_")) + && (CC->user.axlevel >= AxAideU)) { which_floor = extract_int(cmdbuf, 2); - sprintf(CC->upl_path, "./images/floor.%d.gif", which_floor); - } + snprintf(CC->upl_path, sizeof CC->upl_path, + "%s/floor.%d.gif", + ctdl_image_dir, + which_floor); + } - if ( (!strucmp(basenm, "_roompic_")) && (is_room_aide()) ) { - sprintf(CC->upl_path, "./images/room.%d.gif", CC->curr_rm); - } + if ((!strcasecmp(basenm, "_roompic_")) && (is_room_aide())) { + assoc_file_name(CC->upl_path, sizeof CC->upl_path, &CC->room, ctdl_image_dir); + } - if (strlen(CC->upl_path) == 0) { + if (IsEmptyStr(CC->upl_path)) { cprintf("%d Higher access required.\n", - ERROR+HIGHER_ACCESS_REQUIRED); + ERROR + HIGHER_ACCESS_REQUIRED); return; - } + } if (is_this_for_real == 0) { - cprintf("%d Ok to send image\n", OK); + cprintf("%d Ok to send image\n", CIT_OK); return; - } + } - CC->upload_fp = fopen(CC->upl_path,"wb"); + CC->upload_fp = fopen(CC->upl_path, "wb"); if (CC->upload_fp == NULL) { cprintf("%d Cannot open %s: %s\n", - ERROR,CC->upl_path,strerror(errno)); + ERROR + INTERNAL_ERROR, CC->upl_path, strerror(errno)); return; - } - cprintf("%d Ok\n",OK); - CC->upload_type = UPL_IMAGE; } + cprintf("%d Ok\n", CIT_OK); + CC->upload_type = UPL_IMAGE; +} /* * close the download file */ -void cmd_clos(void) { +void cmd_clos(char *cmdbuf) +{ char buf[256]; - + if (CC->download_fp == NULL) { - cprintf("%d You don't have a download file open.\n",ERROR); + cprintf("%d You don't have a download file open.\n", + ERROR + RESOURCE_NOT_OPEN); return; - } + } fclose(CC->download_fp); CC->download_fp = NULL; if (CC->dl_is_net == 1) { CC->dl_is_net = 0; - sprintf(buf,"%s/network/spoolout/%s",BBSDIR,CC->net_node); + snprintf(buf, sizeof buf, + "%s/%s", + ctdl_netout_dir, + CC->net_node); unlink(buf); - } - - cprintf("%d Ok\n",OK); } + cprintf("%d Ok\n", CIT_OK); +} + /* - * abort and upload + * abort an upload */ -void abort_upl(struct CitContext *who) +void abort_upl(CitContext *who) { if (who->upload_fp != NULL) { fclose(who->upload_fp); who->upload_fp = NULL; unlink(CC->upl_path); - } } +} @@ -502,53 +567,73 @@ void abort_upl(struct CitContext *who) void cmd_ucls(char *cmd) { FILE *fp; - long now; - + char upload_notice[512]; + static int seq = 0; + if (CC->upload_fp == NULL) { - cprintf("%d You don't have an upload file open.\n",ERROR); + cprintf("%d You don't have an upload file open.\n", ERROR + RESOURCE_NOT_OPEN); return; - } + } fclose(CC->upload_fp); CC->upload_fp = NULL; - if ((!strucmp(cmd,"1")) && (CC->upload_type != UPL_FILE)) { + if ((!strcasecmp(cmd, "1")) && (CC->upload_type != UPL_FILE)) { + cprintf("%d Upload completed.\n", CIT_OK); + + if (CC->upload_type == UPL_NET) { + char final_filename[PATH_MAX]; + snprintf(final_filename, sizeof final_filename, + "%s/%s.%04lx.%04x", + ctdl_netin_dir, + CC->net_node, + (long)getpid(), + ++seq + ); + + if (link(CC->upl_path, final_filename) == 0) { + unlink(CC->upl_path); + } + else { + syslog(LOG_ALERT, "Cannot link %s to %s: %s\n", + CC->upl_path, final_filename, strerror(errno) + ); + } + + /* FIXME ... here we need to trigger a network run */ + } + CC->upload_type = UPL_FILE; - cprintf("%d Upload completed.\n", OK); return; - } + } - if (!strucmp(cmd,"1")) { - cprintf("%d File '%s' saved.\n",OK,CC->upl_path); - fp = fopen(CC->upl_filedir,"a"); - if (fp==NULL) fp=fopen(CC->upl_filedir,"w"); - if (fp!=NULL) { - fprintf(fp,"%s %s\n",CC->upl_file,CC->upl_comment); + if (!strcasecmp(cmd, "1")) { + cprintf("%d File '%s' saved.\n", CIT_OK, CC->upl_path); + fp = fopen(CC->upl_filedir, "a"); + if (fp == NULL) { + fp = fopen(CC->upl_filedir, "w"); + } + if (fp != NULL) { + fprintf(fp, "%s %s %s\n", CC->upl_file, + CC->upl_mimetype, + CC->upl_comment); fclose(fp); - } + } /* put together an upload notice */ - time(&now); - fp=fopen(CC->temp,"wb"); - putc(255,fp); - putc(MES_NORMAL,fp); - putc(0,fp); - fprintf(fp,"Pcit%ld",CC->usersupp.usernum); putc(0,fp); - fprintf(fp,"T%ld",now); putc(0,fp); - fprintf(fp,"A%s",CC->curr_user); putc(0,fp); - fprintf(fp,"O%s",CC->quickroom.QRname); putc(0,fp); - fprintf(fp,"N%s",NODENAME); putc(0,fp); putc('M',fp); - fprintf(fp,"NEW UPLOAD: '%s'\n %s\n",CC->upl_file,CC->upl_comment); - putc(0,fp); - fclose(fp); - save_message(CC->temp, "", 0, M_LOCAL, 1); - - } - else { + snprintf(upload_notice, sizeof upload_notice, + "NEW UPLOAD: '%s'\n %s\n%s\n", + CC->upl_file, + CC->upl_comment, + CC->upl_mimetype); + quickie_message(CC->curr_user, NULL, NULL, CC->room.QRname, + upload_notice, 0, NULL); + } else { abort_upl(CC); - cprintf("%d File '%s' aborted.\n",OK,CC->upl_path); - } + cprintf("%d File '%s' aborted.\n", CIT_OK, CC->upl_path); } +} + /* * read from the download file @@ -556,30 +641,35 @@ void cmd_ucls(char *cmd) void cmd_read(char *cmdbuf) { long start_pos; - int bytes; - char buf[4096]; + size_t bytes; + char buf[SIZ]; - start_pos = extract_long(cmdbuf,0); - bytes = extract_int(cmdbuf,1); - - if (CC->download_fp == NULL) { - cprintf("%d You don't have a download file open.\n",ERROR); - return; - } + /* The client will transmit its requested offset and byte count */ + start_pos = extract_long(cmdbuf, 0); + bytes = extract_int(cmdbuf, 1); - if (bytes > 4096) { - cprintf("%d You may not read more than 4096 bytes.\n",ERROR); + if (CC->download_fp == NULL) { + cprintf("%d You don't have a download file open.\n", + ERROR + RESOURCE_NOT_OPEN); return; - } - - if (CC->dl_is_net) if (bytes>64) bytes = 64; /**** FIX ****/ + } - fseek(CC->download_fp,start_pos,0); - fread(buf,bytes,1,CC->download_fp); - cprintf("%d %d\n",BINARY_FOLLOWS,bytes); - client_write(buf, bytes); + /* If necessary, reduce the byte count to the size of our buffer */ + if (bytes > sizeof(buf)) { + bytes = sizeof(buf); } + fseek(CC->download_fp, start_pos, 0); + bytes = fread(buf, 1, bytes, CC->download_fp); + if (bytes > 0) { + /* Tell the client the actual byte count and transmit it */ + cprintf("%d %d\n", BINARY_FOLLOWS, (int)bytes); + client_write(buf, bytes); + } + else { + cprintf("%d %s\n", ERROR, strerror(errno)); + } +} /* @@ -588,44 +678,37 @@ void cmd_read(char *cmdbuf) void cmd_writ(char *cmdbuf) { int bytes; - char buf[4096]; + char *buf; + int rv; + + unbuffer_output(); + + bytes = extract_int(cmdbuf, 0); - bytes = extract_int(cmdbuf,0); - if (CC->upload_fp == NULL) { - cprintf("%d You don't have an upload file open.\n",ERROR); + cprintf("%d You don't have an upload file open.\n", ERROR + RESOURCE_NOT_OPEN); return; - } + } - if (bytes > 4096) { - cprintf("%d You may not write more than 4096 bytes.\n",ERROR); + if (bytes > 100000) { + cprintf("%d You may not write more than 100000 bytes.\n", + ERROR + TOO_BIG); return; - } - - if (CC->upload_type==UPL_NET) if (bytes > 64) bytes = 64; /*** FIX ***/ + } - cprintf("%d %d\n",SEND_BINARY,bytes); + cprintf("%d %d\n", SEND_BINARY, bytes); + buf = malloc(bytes + 1); client_read(buf, bytes); - fwrite(buf,bytes,1,CC->upload_fp); + rv = fwrite(buf, bytes, 1, CC->upload_fp); + if (rv == -1) { + syslog(LOG_EMERG, "Couldn't write: %s\n", + strerror(errno)); } + free(buf); +} -/* - * cmd_netp() - identify as network poll session - */ -void cmd_netp(char *cmdbuf) -{ - char buf[256]; - - extract(buf,cmdbuf,1); - if (strucmp(buf,config.c_net_password)) { - cprintf("%d authentication failed\n",ERROR); - return; - } - extract(CC->net_node,cmdbuf,0); - cprintf("%d authenticated as network node '%s'\n",OK,CC->net_node); - } /* * cmd_ndop() - open a network spool file for downloading @@ -635,32 +718,37 @@ void cmd_ndop(char *cmdbuf) char pathname[256]; struct stat statbuf; - if (strlen(CC->net_node)==0) { + if (IsEmptyStr(CC->net_node)) { cprintf("%d Not authenticated as a network node.\n", - ERROR+NOT_LOGGED_IN); + ERROR + NOT_LOGGED_IN); return; - } + } if (CC->download_fp != NULL) { - cprintf("%d You already have a download file open.\n",ERROR); + cprintf("%d You already have a download file open.\n", + ERROR + RESOURCE_BUSY); return; - } + } - sprintf(pathname,"%s/network/spoolout/%s",BBSDIR,CC->net_node); + snprintf(pathname, sizeof pathname, + "%s/%s", + ctdl_netout_dir, + CC->net_node); /* first open the file in append mode in order to create a * zero-length file if it doesn't already exist */ - CC->download_fp = fopen(pathname,"a"); - fclose(CC->download_fp); + CC->download_fp = fopen(pathname, "a"); + if (CC->download_fp != NULL) + fclose(CC->download_fp); /* now open it */ - CC->download_fp = fopen(pathname,"r"); - if (CC->download_fp==NULL) { + CC->download_fp = fopen(pathname, "r"); + if (CC->download_fp == NULL) { cprintf("%d cannot open %s: %s\n", - ERROR,pathname,strerror(errno)); + ERROR + INTERNAL_ERROR, pathname, strerror(errno)); return; - } + } /* set this flag so other routines know that the download file @@ -668,45 +756,79 @@ void cmd_ndop(char *cmdbuf) */ CC->dl_is_net = 1; - stat(pathname,&statbuf); - cprintf("%d %ld\n",OK,statbuf.st_size); - } + stat(pathname, &statbuf); + CC->download_fp_total = statbuf.st_size; + cprintf("%d %ld\n", CIT_OK, (long)statbuf.st_size); +} /* * cmd_nuop() - open a network spool file for uploading */ void cmd_nuop(char *cmdbuf) { - if (strlen(CC->net_node)==0) { + static int seq = 1; + + if (IsEmptyStr(CC->net_node)) { cprintf("%d Not authenticated as a network node.\n", - ERROR+NOT_LOGGED_IN); + ERROR + NOT_LOGGED_IN); return; - } + } if (CC->upload_fp != NULL) { - cprintf("%d You already have an upload file open.\n",ERROR); + cprintf("%d You already have an upload file open.\n", + ERROR + RESOURCE_BUSY); return; - } + } - sprintf(CC->upl_path,"%s/network/spoolin/%s.%d", - BBSDIR,CC->net_node,getpid()); + snprintf(CC->upl_path, sizeof CC->upl_path, + "%s/%s.%04lx.%04x", + ctdl_nettmp_dir, + CC->net_node, + (long)getpid(), + ++seq); - CC->upload_fp = fopen(CC->upl_path,"r"); + CC->upload_fp = fopen(CC->upl_path, "r"); if (CC->upload_fp != NULL) { fclose(CC->upload_fp); CC->upload_fp = NULL; cprintf("%d '%s' already exists\n", - ERROR+ALREADY_EXISTS,CC->upl_path); + ERROR + ALREADY_EXISTS, CC->upl_path); return; - } + } - CC->upload_fp = fopen(CC->upl_path,"w"); + CC->upload_fp = fopen(CC->upl_path, "w"); if (CC->upload_fp == NULL) { cprintf("%d Cannot open %s: %s\n", - ERROR,CC->upl_path,strerror(errno)); + ERROR + INTERNAL_ERROR, CC->upl_path, strerror(errno)); return; - } + } CC->upload_type = UPL_NET; - cprintf("%d Ok\n",OK); + cprintf("%d Ok\n", CIT_OK); +} + + +/*****************************************************************************/ +/* MODULE INITIALIZATION STUFF */ +/*****************************************************************************/ + +CTDL_MODULE_INIT(file_ops) +{ + if (!threading) { + CtdlRegisterProtoHook(cmd_delf, "DELF", "Delete a file"); + CtdlRegisterProtoHook(cmd_movf, "MOVF", "Move a file"); + CtdlRegisterProtoHook(cmd_open, "OPEN", "Open a download file transfer"); + CtdlRegisterProtoHook(cmd_clos, "CLOS", "Close a download file transfer"); + CtdlRegisterProtoHook(cmd_uopn, "UOPN", "Open an upload file transfer"); + CtdlRegisterProtoHook(cmd_ucls, "UCLS", "Close an upload file transfer"); + CtdlRegisterProtoHook(cmd_read, "READ", "File transfer read operation"); + CtdlRegisterProtoHook(cmd_writ, "WRIT", "File transfer write operation"); + CtdlRegisterProtoHook(cmd_ndop, "NDOP", "Open a network spool file for download"); + CtdlRegisterProtoHook(cmd_nuop, "NUOP", "Open a network spool file for upload"); + CtdlRegisterProtoHook(cmd_oimg, "OIMG", "Open an image file for download"); + CtdlRegisterProtoHook(cmd_uimg, "UIMG", "Upload an image file"); + CtdlRegisterCleanupHook(cleanup_nttlist); } + /* return our Subversion id for the Log */ + return "file_ops"; +}