X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Ffile_ops.c;h=4ec3f8e5149029531728344a191f7f38b80c6105;hb=21ec54850b65bbff0c44874cc1de4fe8cf8f7e7d;hp=bf4cee5b1f32c1393805b1b37868453e355b8a4f;hpb=8896f6d392af58e432577e100353f5ffb4d02e21;p=citadel.git diff --git a/citadel/file_ops.c b/citadel/file_ops.c index bf4cee5b1..4ec3f8e51 100644 --- a/citadel/file_ops.c +++ b/citadel/file_ops.c @@ -1,8 +1,5 @@ /* - * $Id$ - * * Server functions which handle file transfers and room directories. - * */ #include "sysdep.h" @@ -15,6 +12,7 @@ #include #include #include +#include #if TIME_WITH_SYS_TIME # include @@ -28,29 +26,31 @@ #endif #include +#include #include "citadel.h" #include "server.h" -#include "serv_extensions.h" #include "config.h" #include "file_ops.h" #include "sysdep_decls.h" -#include "user_ops.h" #include "support.h" #include "room_ops.h" #include "msgbase.h" -#include "tools.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 */ -int network_talking_to(char *nodename, int operation) { +static char *nttlist = NULL; +int network_talking_to(const char *nodename, int operation) { - static char *nttlist = NULL; char *ptr = NULL; int i; char buf[SIZ]; @@ -71,13 +71,13 @@ int network_talking_to(char *nodename, int operation) { case NTT_REMOVE: if (nttlist == NULL) break; - if (strlen(nttlist) == 0) break; + if (IsEmptyStr(nttlist)) break; ptr = malloc(strlen(nttlist)); if (ptr == NULL) break; strcpy(ptr, ""); for (i = 0; i < num_tokens(nttlist, '|'); ++i) { extract_token(buf, nttlist, i, '|', sizeof buf); - if ( (strlen(buf) > 0) + if ( (!IsEmptyStr(buf)) && (strcasecmp(buf, nodename)) ) { strcat(ptr, buf); strcat(ptr, "|"); @@ -89,7 +89,7 @@ int network_talking_to(char *nodename, int operation) { case NTT_CHECK: if (nttlist == NULL) break; - if (strlen(nttlist) == 0) break; + if (IsEmptyStr(nttlist)) break; for (i = 0; i < num_tokens(nttlist, '|'); ++i) { extract_token(buf, nttlist, i, '|', sizeof buf); if (!strcasecmp(buf, nodename)) ++retval; @@ -97,11 +97,19 @@ int network_talking_to(char *nodename, int operation) { break; } - if (nttlist != NULL) lprintf(CTDL_DEBUG, "nttlist=<%s>\n", nttlist); + if (nttlist != NULL) syslog(LOG_DEBUG, "nttlist=<%s>\n", nttlist); end_critical_section(S_NTTLIST); return(retval); } +void cleanup_nttlist(void) +{ + begin_critical_section(S_NTTLIST); + if (nttlist != NULL) + free(nttlist); + nttlist = NULL; + end_critical_section(S_NTTLIST); +} @@ -122,13 +130,13 @@ void cmd_delf(char *filename) return; } - if (strlen(filename) == 0) { + if (IsEmptyStr(filename)) { cprintf("%d You must specify a file name.\n", ERROR + FILE_NOT_FOUND); return; } - for (a = 0; a < strlen(filename); ++a) { - if (filename[a] == '/') { + for (a = 0; !IsEmptyStr(&filename[a]); ++a) { + if ( (filename[a] == '/') || (filename[a] == '\\') ) { filename[a] = '_'; } } @@ -161,6 +169,7 @@ void cmd_movf(char *cmdbuf) char buf[PATH_MAX]; int a; struct ctdlroom qrbuf; + int rv = 0; extract_token(filename, cmdbuf, 0, '|', sizeof filename); extract_token(newroom, cmdbuf, 1, '|', sizeof newroom); @@ -173,14 +182,14 @@ void cmd_movf(char *cmdbuf) return; } - if (strlen(filename) == 0) { + if (IsEmptyStr(filename)) { cprintf("%d You must specify a file name.\n", ERROR + FILE_NOT_FOUND); return; } - for (a = 0; a < strlen(filename); ++a) { - if (filename[a] == '/') { + for (a = 0; !IsEmptyStr(&filename[a]); ++a) { + if ( (filename[a] == '/') || (filename[a] == '\\') ) { filename[a] = '_'; } } @@ -192,7 +201,7 @@ void cmd_movf(char *cmdbuf) return; } - if (getroom(&qrbuf, newroom) != 0) { + if (CtdlGetRoom(&qrbuf, newroom) != 0) { cprintf("%d '%s' does not exist.\n", ERROR + ROOM_NOT_FOUND, newroom); return; } @@ -212,109 +221,13 @@ void cmd_movf(char *cmdbuf) /* this is a crude method of copying the file description */ snprintf(buf, sizeof buf, - "cat ./files/%s/filedir |grep %s >>./files/%s/filedir", + "cat ./files/%s/filedir |grep \"%s\" >>./files/%s/filedir", CC->room.QRdirname, filename, qrbuf.QRdirname); - system(buf); + 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]; - char outfile[256]; - int a, e; - time_t now; - FILE *ofp; - static int seq = 1; - - extract_token(filename, cmdbuf, 0, '|', sizeof filename); - extract_token(destsys, cmdbuf, 1, '|', sizeof destsys); - - if (CtdlAccessCheck(ac_room_aide)) return; - - if ((CC->room.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; a < strlen(filename); ++a) { - if (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); - return; - } - snprintf(buf, sizeof buf, "sysop@%s", destsys); - e = alias(buf); - if (e != MES_IGNET) { - cprintf("%d No such system: '%s'\n", - ERROR + NO_SUCH_SYSTEM, destsys); - return; - } - snprintf(outfile, sizeof outfile, - "%s/nsf.%04lx.%04x", - ctdl_netin_dir, - (long)getpid(), ++seq); - ofp = fopen(outfile, "a"); - if (ofp == NULL) { - cprintf("%d internal error\n", ERROR + INTERNAL_ERROR); - return; - } - - putc(255, ofp); - putc(MES_NORMAL, ofp); - putc(0, ofp); - fprintf(ofp, "Pcit%ld", CC->user.usernum); - putc(0, ofp); - time(&now); - fprintf(ofp, "T%ld", (long) now); - putc(0, ofp); - fprintf(ofp, "A%s", CC->user.fullname); - putc(0, ofp); - fprintf(ofp, "O%s", CC->room.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); - - snprintf(buf, sizeof buf, - "cd %s/%s; uuencode %s <%s 2>/dev/null >>%s", - ctdl_file_dir, - /* FIXME: detect uuencode while installation? or inline */ - CC->room.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", CIT_OK, filename, - destsys); - /* FIXME start a network run here. */ - return; -} - /* * 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 @@ -322,13 +235,14 @@ void cmd_netf(char *cmdbuf) * It examines the file and displays the OK result code and some information * about the file. NOTE: this stuff is Unix dependent. */ -void OpenCmdResult(char *filename, char *mime_type) +void OpenCmdResult(char *filename, const char *mime_type) { struct stat statbuf; time_t modtime; long filesize; fstat(fileno(CC->download_fp), &statbuf); + CC->download_fp_total = statbuf.st_size; filesize = (long) statbuf.st_size; modtime = (time_t) statbuf.st_mtime; @@ -356,7 +270,7 @@ void cmd_open(char *cmdbuf) return; } - if (strlen(filename) == 0) { + if (IsEmptyStr(filename)) { cprintf("%d You must specify a file name.\n", ERROR + FILE_NOT_FOUND); return; @@ -368,8 +282,8 @@ void cmd_open(char *cmdbuf) return; } - for (a = 0; a < strlen(filename); ++a) { - if (filename[a] == '/') { + for (a = 0; !IsEmptyStr(&filename[a]); ++a) { + if ( (filename[a] == '/') || (filename[a] == '\\') ) { filename[a] = '_'; } } @@ -396,14 +310,16 @@ void cmd_oimg(char *cmdbuf) { char filename[256]; char pathname[PATH_MAX]; + char MimeTestBuf[32]; struct ctdluser usbuf; char which_user[USERNAME_SIZE]; int which_floor; int a; + int rv; 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); return; @@ -417,43 +333,54 @@ void cmd_oimg(char *cmdbuf) if (!strcasecmp(filename, "_userpic_")) { extract_token(which_user, cmdbuf, 1, '|', sizeof which_user); - if (getuser(&usbuf, which_user) != 0) { + if (CtdlGetUser(&usbuf, which_user) != 0) { cprintf("%d No such user.\n", ERROR + NO_SUCH_USER); return; } snprintf(pathname, sizeof pathname, - "%s/%ld.gif", + "%s/%ld", ctdl_usrpic_dir, usbuf.usernum); } else if (!strcasecmp(filename, "_floorpic_")) { which_floor = extract_int(cmdbuf, 1); snprintf(pathname, sizeof pathname, - "%s/floor.%d.gif", + "%s/floor.%d", ctdl_image_dir, which_floor); } else if (!strcasecmp(filename, "_roompic_")) { assoc_file_name(pathname, sizeof pathname, &CC->room, ctdl_image_dir); } else { - for (a = 0; a < strlen(filename); ++a) { + for (a = 0; !IsEmptyStr(&filename[a]); ++a) { filename[a] = tolower(filename[a]); - if (filename[a] == '/') { + if ( (filename[a] == '/') || (filename[a] == '\\') ) { filename[a] = '_'; } } snprintf(pathname, sizeof pathname, - "%s/%s.gif", + "%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)); 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(pathname, "image/gif"); + rewind (CC->download_fp); + OpenCmdResult(pathname, GuessMimeType(&MimeTestBuf[0], 32)); } /* @@ -464,7 +391,8 @@ void cmd_uopn(char *cmdbuf) int a; extract_token(CC->upl_file, cmdbuf, 0, '|', sizeof CC->upl_file); - extract_token(CC->upl_comment, cmdbuf, 1, '|', sizeof CC->upl_comment); + extract_token(CC->upl_mimetype, cmdbuf, 1, '|', sizeof CC->upl_mimetype); + extract_token(CC->upl_comment, cmdbuf, 2, '|', sizeof CC->upl_comment); if (CtdlAccessCheck(ac_logged_in)) return; @@ -474,7 +402,7 @@ void cmd_uopn(char *cmdbuf) 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); return; @@ -486,8 +414,8 @@ void cmd_uopn(char *cmdbuf) return; } - for (a = 0; a < strlen(CC->upl_file); ++a) { - if (CC->upl_file[a] == '/') { + for (a = 0; !IsEmptyStr(&CC->upl_file[a]); ++a) { + if ( (CC->upl_file[a] == '/') || (CC->upl_file[a] == '\\') ) { CC->upl_file[a] = '_'; } } @@ -536,7 +464,8 @@ void cmd_uimg(char *cmdbuf) } is_this_for_real = extract_int(cmdbuf, 0); - extract_token(basenm, cmdbuf, 1, '|', sizeof basenm); + 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 + RESOURCE_BUSY); @@ -545,14 +474,14 @@ void cmd_uimg(char *cmdbuf) strcpy(CC->upl_path, ""); - for (a = 0; a < strlen(basenm); ++a) { + for (a = 0; !IsEmptyStr(&basenm[a]); ++a) { basenm[a] = tolower(basenm[a]); - if (basenm[a] == '/') { + if ( (basenm[a] == '/') || (basenm[a] == '\\') ) { basenm[a] = '_'; } } - if (CC->user.axlevel >= 6) { + if (CC->user.axlevel >= AxAideU) { snprintf(CC->upl_path, sizeof CC->upl_path, "%s/%s", ctdl_image_dir, @@ -567,7 +496,7 @@ void cmd_uimg(char *cmdbuf) } if ((!strcasecmp(basenm, "_floorpic_")) - && (CC->user.axlevel >= 6)) { + && (CC->user.axlevel >= AxAideU)) { which_floor = extract_int(cmdbuf, 2); snprintf(CC->upl_path, sizeof CC->upl_path, "%s/floor.%d.gif", @@ -579,7 +508,7 @@ void cmd_uimg(char *cmdbuf) 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); return; @@ -604,7 +533,7 @@ void cmd_uimg(char *cmdbuf) /* * close the download file */ -void cmd_clos(void) +void cmd_clos(char *cmdbuf) { char buf[256]; @@ -633,7 +562,7 @@ void cmd_clos(void) /* * abort an upload */ -void abort_upl(struct CitContext *who) +void abort_upl(CitContext *who) { if (who->upload_fp != NULL) { fclose(who->upload_fp); @@ -651,6 +580,7 @@ void cmd_ucls(char *cmd) { FILE *fp; 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 + RESOURCE_NOT_OPEN); @@ -661,11 +591,31 @@ void cmd_ucls(char *cmd) CC->upload_fp = NULL; if ((!strcasecmp(cmd, "1")) && (CC->upload_type != UPL_FILE)) { - CC->upload_type = UPL_FILE; cprintf("%d Upload completed.\n", CIT_OK); - /* FIXME ... here we need to trigger a network run */ + 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; return; } @@ -676,15 +626,18 @@ void cmd_ucls(char *cmd) fp = fopen(CC->upl_filedir, "w"); } if (fp != NULL) { - fprintf(fp, "%s %s\n", CC->upl_file, + fprintf(fp, "%s %s %s\n", CC->upl_file, + CC->upl_mimetype, CC->upl_comment); fclose(fp); } /* put together an upload notice */ snprintf(upload_notice, sizeof upload_notice, - "NEW UPLOAD: '%s'\n %s\n", - CC->upl_file, CC->upl_comment); + "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 { @@ -694,7 +647,6 @@ void cmd_ucls(char *cmd) } - /* * read from the download file */ @@ -702,9 +654,9 @@ void cmd_read(char *cmdbuf) { long start_pos; size_t bytes; - size_t actual_bytes; - char *buf = NULL; + char buf[SIZ]; + /* The client will transmit its requested offset and byte count */ start_pos = extract_long(cmdbuf, 0); bytes = extract_int(cmdbuf, 1); @@ -714,18 +666,24 @@ void cmd_read(char *cmdbuf) return; } - if (bytes > 100000) bytes = 100000; - buf = malloc(bytes + 1); + /* 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); - actual_bytes = fread(buf, 1, bytes, CC->download_fp); - cprintf("%d %d\n", BINARY_FOLLOWS, (int)actual_bytes); - client_write(buf, actual_bytes); - free(buf); + 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)); + } } - /* * write to the upload file */ @@ -733,6 +691,7 @@ void cmd_writ(char *cmdbuf) { int bytes; char *buf; + int rv; unbuffer_output(); @@ -752,7 +711,11 @@ void cmd_writ(char *cmdbuf) 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); } @@ -767,7 +730,7 @@ 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); return; @@ -806,6 +769,7 @@ void cmd_ndop(char *cmdbuf) CC->dl_is_net = 1; stat(pathname, &statbuf); + CC->download_fp_total = statbuf.st_size; cprintf("%d %ld\n", CIT_OK, (long)statbuf.st_size); } @@ -816,7 +780,7 @@ void cmd_nuop(char *cmdbuf) { static int seq = 1; - if (strlen(CC->net_node) == 0) { + if (IsEmptyStr(CC->net_node)) { cprintf("%d Not authenticated as a network node.\n", ERROR + NOT_LOGGED_IN); return; @@ -830,7 +794,7 @@ void cmd_nuop(char *cmdbuf) snprintf(CC->upl_path, sizeof CC->upl_path, "%s/%s.%04lx.%04x", - ctdl_netin_dir, + ctdl_nettmp_dir, CC->net_node, (long)getpid(), ++seq); @@ -854,3 +818,29 @@ void cmd_nuop(char *cmdbuf) CC->upload_type = UPL_NET; 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"; +}