4 * Server functions which handle file transfers and room directories.
19 #if TIME_WITH_SYS_TIME
20 # include <sys/time.h>
24 # include <sys/time.h>
35 #include "sysdep_decls.h"
41 #include "citserver.h"
48 * network_talking_to() -- concurrency checker
50 int network_talking_to(char *nodename, int operation) {
52 static char *nttlist = NULL;
58 begin_critical_section(S_NTTLIST);
63 if (nttlist == NULL) nttlist = strdup("");
64 if (nttlist == NULL) break;
65 nttlist = (char *)realloc(nttlist,
66 (strlen(nttlist) + strlen(nodename) + 3) );
68 strcat(nttlist, nodename);
72 if (nttlist == NULL) break;
73 if (IsEmptyStr(nttlist)) break;
74 ptr = malloc(strlen(nttlist));
75 if (ptr == NULL) break;
77 for (i = 0; i < num_tokens(nttlist, '|'); ++i) {
78 extract_token(buf, nttlist, i, '|', sizeof buf);
79 if ( (!IsEmptyStr(buf))
80 && (strcasecmp(buf, nodename)) ) {
90 if (nttlist == NULL) break;
91 if (IsEmptyStr(nttlist)) break;
92 for (i = 0; i < num_tokens(nttlist, '|'); ++i) {
93 extract_token(buf, nttlist, i, '|', sizeof buf);
94 if (!strcasecmp(buf, nodename)) ++retval;
99 if (nttlist != NULL) lprintf(CTDL_DEBUG, "nttlist=<%s>\n", nttlist);
100 end_critical_section(S_NTTLIST);
108 * Server command to delete a file from a room's directory
110 void cmd_delf(char *filename)
115 if (CtdlAccessCheck(ac_room_aide))
118 if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
119 cprintf("%d No directory in this room.\n",
124 if (IsEmptyStr(filename)) {
125 cprintf("%d You must specify a file name.\n",
126 ERROR + FILE_NOT_FOUND);
129 for (a = 0; !IsEmptyStr(&filename[a]); ++a) {
130 if (filename[a] == '/') {
134 snprintf(pathname, sizeof pathname,
137 CC->room.QRdirname, filename);
138 a = unlink(pathname);
140 cprintf("%d File '%s' deleted.\n", CIT_OK, pathname);
143 cprintf("%d File '%s' not found.\n",
144 ERROR + FILE_NOT_FOUND, pathname);
152 * move a file from one room directory to another
154 void cmd_movf(char *cmdbuf)
156 char filename[PATH_MAX];
157 char pathname[PATH_MAX];
158 char newpath[PATH_MAX];
159 char newroom[ROOMNAMELEN];
162 struct ctdlroom qrbuf;
164 extract_token(filename, cmdbuf, 0, '|', sizeof filename);
165 extract_token(newroom, cmdbuf, 1, '|', sizeof newroom);
167 if (CtdlAccessCheck(ac_room_aide)) return;
169 if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
170 cprintf("%d No directory in this room.\n",
175 if (IsEmptyStr(filename)) {
176 cprintf("%d You must specify a file name.\n",
177 ERROR + FILE_NOT_FOUND);
181 for (a = 0; !IsEmptyStr(&filename[a]); ++a) {
182 if (filename[a] == '/') {
186 snprintf(pathname, sizeof pathname, "./files/%s/%s",
187 CC->room.QRdirname, filename);
188 if (access(pathname, 0) != 0) {
189 cprintf("%d File '%s' not found.\n",
190 ERROR + FILE_NOT_FOUND, pathname);
194 if (getroom(&qrbuf, newroom) != 0) {
195 cprintf("%d '%s' does not exist.\n", ERROR + ROOM_NOT_FOUND, newroom);
198 if ((qrbuf.QRflags & QR_DIRECTORY) == 0) {
199 cprintf("%d '%s' is not a directory room.\n",
200 ERROR + NOT_HERE, qrbuf.QRname);
203 snprintf(newpath, sizeof newpath, "./files/%s/%s", qrbuf.QRdirname,
205 if (link(pathname, newpath) != 0) {
206 cprintf("%d Couldn't move file: %s\n", ERROR + INTERNAL_ERROR,
212 /* this is a crude method of copying the file description */
213 snprintf(buf, sizeof buf,
214 "cat ./files/%s/filedir |grep %s >>./files/%s/filedir",
215 CC->room.QRdirname, filename, qrbuf.QRdirname);
217 cprintf("%d File '%s' has been moved.\n", CIT_OK, filename);
222 * send a file over the net
224 void cmd_netf(char *cmdbuf)
226 char pathname[256], filename[256], destsys[256], buf[256];
233 extract_token(filename, cmdbuf, 0, '|', sizeof filename);
234 extract_token(destsys, cmdbuf, 1, '|', sizeof destsys);
236 if (CtdlAccessCheck(ac_room_aide)) return;
238 if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
239 cprintf("%d No directory in this room.\n",
244 if (IsEmptyStr(filename)) {
245 cprintf("%d You must specify a file name.\n",
246 ERROR + FILE_NOT_FOUND);
250 for (a = 0; !IsEmptyStr(&filename[a]); ++a) {
251 if (filename[a] == '/') {
255 snprintf(pathname, sizeof pathname, "./files/%s/%s",
256 CC->room.QRdirname, filename);
257 if (access(pathname, 0) != 0) {
258 cprintf("%d File '%s' not found.\n",
259 ERROR + FILE_NOT_FOUND, pathname);
262 snprintf(buf, sizeof buf, "sysop@%s", destsys);
264 if (e != MES_IGNET) {
265 cprintf("%d No such system: '%s'\n",
266 ERROR + NO_SUCH_SYSTEM, destsys);
269 snprintf(outfile, sizeof outfile,
272 (long)getpid(), ++seq);
273 ofp = fopen(outfile, "a");
275 cprintf("%d internal error\n", ERROR + INTERNAL_ERROR);
280 putc(MES_NORMAL, ofp);
282 fprintf(ofp, "P%s", CC->user.fullname);
285 fprintf(ofp, "T%ld", (long) now);
287 fprintf(ofp, "A%s", CC->user.fullname);
289 fprintf(ofp, "O%s", CC->room.QRname);
291 fprintf(ofp, "N%s", NODENAME);
293 fprintf(ofp, "D%s", destsys);
295 fprintf(ofp, "SFILE");
300 snprintf(buf, sizeof buf,
301 "cd %s/%s; uuencode %s <%s 2>/dev/null >>%s",
303 /* FIXME: detect uuencode while installation? or inline */
304 CC->room.QRdirname, filename, filename, outfile);
307 ofp = fopen(outfile, "a");
311 cprintf("%d File '%s' has been sent to %s.\n", CIT_OK, filename,
313 /* FIXME start a network run here. */
318 * This code is common to all commands which open a file for downloading,
319 * regardless of whether it's a file from the directory, an image, a network
320 * spool file, a MIME attachment, etc.
321 * It examines the file and displays the OK result code and some information
322 * about the file. NOTE: this stuff is Unix dependent.
324 void OpenCmdResult(char *filename, char *mime_type)
330 fstat(fileno(CC->download_fp), &statbuf);
331 filesize = (long) statbuf.st_size;
332 modtime = (time_t) statbuf.st_mtime;
334 cprintf("%d %ld|%ld|%s|%s\n",
335 CIT_OK, filesize, (long)modtime, filename, mime_type);
340 * open a file for downloading
342 void cmd_open(char *cmdbuf)
345 char pathname[PATH_MAX];
348 extract_token(filename, cmdbuf, 0, '|', sizeof filename);
350 if (CtdlAccessCheck(ac_logged_in)) return;
352 if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
353 cprintf("%d No directory in this room.\n",
358 if (IsEmptyStr(filename)) {
359 cprintf("%d You must specify a file name.\n",
360 ERROR + FILE_NOT_FOUND);
364 if (CC->download_fp != NULL) {
365 cprintf("%d You already have a download file open.\n",
366 ERROR + RESOURCE_BUSY);
370 for (a = 0; !IsEmptyStr(&filename[a]); ++a) {
371 if (filename[a] == '/') {
376 snprintf(pathname, sizeof pathname,
379 CC->room.QRdirname, filename);
380 CC->download_fp = fopen(pathname, "r");
382 if (CC->download_fp == NULL) {
383 cprintf("%d cannot open %s: %s\n",
384 ERROR + INTERNAL_ERROR, pathname, strerror(errno));
388 OpenCmdResult(filename, "application/octet-stream");
394 void cmd_oimg(char *cmdbuf)
397 char pathname[PATH_MAX];
398 struct ctdluser usbuf;
399 char which_user[USERNAME_SIZE];
403 extract_token(filename, cmdbuf, 0, '|', sizeof filename);
405 if (IsEmptyStr(filename)) {
406 cprintf("%d You must specify a file name.\n",
407 ERROR + FILE_NOT_FOUND);
411 if (CC->download_fp != NULL) {
412 cprintf("%d You already have a download file open.\n",
413 ERROR + RESOURCE_BUSY);
417 if (!strcasecmp(filename, "_userpic_")) {
418 extract_token(which_user, cmdbuf, 1, '|', sizeof which_user);
419 if (getuser(&usbuf, which_user) != 0) {
420 cprintf("%d No such user.\n",
421 ERROR + NO_SUCH_USER);
424 snprintf(pathname, sizeof pathname,
428 } else if (!strcasecmp(filename, "_floorpic_")) {
429 which_floor = extract_int(cmdbuf, 1);
430 snprintf(pathname, sizeof pathname,
432 ctdl_image_dir, which_floor);
433 } else if (!strcasecmp(filename, "_roompic_")) {
434 assoc_file_name(pathname, sizeof pathname, &CC->room, ctdl_image_dir);
436 for (a = 0; !IsEmptyStr(&filename[0]); ++a) {
437 filename[a] = tolower(filename[a]);
438 if (filename[a] == '/') {
442 snprintf(pathname, sizeof pathname,
448 CC->download_fp = fopen(pathname, "rb");
449 if (CC->download_fp == NULL) {
450 cprintf("%d Cannot open %s: %s\n",
451 ERROR + FILE_NOT_FOUND, pathname, strerror(errno));
455 OpenCmdResult(pathname, "image/gif");
459 * open a file for uploading
461 void cmd_uopn(char *cmdbuf)
465 extract_token(CC->upl_file, cmdbuf, 0, '|', sizeof CC->upl_file);
466 extract_token(CC->upl_comment, cmdbuf, 1, '|', sizeof CC->upl_comment);
468 if (CtdlAccessCheck(ac_logged_in)) return;
470 if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
471 cprintf("%d No directory in this room.\n",
476 if (IsEmptyStr(CC->upl_file)) {
477 cprintf("%d You must specify a file name.\n",
478 ERROR + FILE_NOT_FOUND);
482 if (CC->upload_fp != NULL) {
483 cprintf("%d You already have a upload file open.\n",
484 ERROR + RESOURCE_BUSY);
488 for (a = 0; !IsEmptyStr(&CC->upl_file[a]); ++a) {
489 if (CC->upl_file[a] == '/') {
490 CC->upl_file[a] = '_';
493 snprintf(CC->upl_path, sizeof CC->upl_path,
496 CC->room.QRdirname, CC->upl_file);
497 snprintf(CC->upl_filedir, sizeof CC->upl_filedir,
502 CC->upload_fp = fopen(CC->upl_path, "r");
503 if (CC->upload_fp != NULL) {
504 fclose(CC->upload_fp);
505 CC->upload_fp = NULL;
506 cprintf("%d '%s' already exists\n",
507 ERROR + ALREADY_EXISTS, CC->upl_path);
511 CC->upload_fp = fopen(CC->upl_path, "wb");
512 if (CC->upload_fp == NULL) {
513 cprintf("%d Cannot open %s: %s\n",
514 ERROR + INTERNAL_ERROR, CC->upl_path, strerror(errno));
517 cprintf("%d Ok\n", CIT_OK);
523 * open an image file for uploading
525 void cmd_uimg(char *cmdbuf)
527 int is_this_for_real;
532 if (num_parms(cmdbuf) < 2) {
533 cprintf("%d Usage error.\n", ERROR + ILLEGAL_VALUE);
537 is_this_for_real = extract_int(cmdbuf, 0);
538 extract_token(basenm, cmdbuf, 1, '|', sizeof basenm);
539 if (CC->upload_fp != NULL) {
540 cprintf("%d You already have an upload file open.\n",
541 ERROR + RESOURCE_BUSY);
545 strcpy(CC->upl_path, "");
547 for (a = 0; !IsEmptyStr(&basenm[a]); ++a) {
548 basenm[a] = tolower(basenm[a]);
549 if (basenm[a] == '/') {
554 if (CC->user.axlevel >= 6) {
555 snprintf(CC->upl_path, sizeof CC->upl_path,
561 if (!strcasecmp(basenm, "_userpic_")) {
562 snprintf(CC->upl_path, sizeof CC->upl_path,
568 if ((!strcasecmp(basenm, "_floorpic_"))
569 && (CC->user.axlevel >= 6)) {
570 which_floor = extract_int(cmdbuf, 2);
571 snprintf(CC->upl_path, sizeof CC->upl_path,
577 if ((!strcasecmp(basenm, "_roompic_")) && (is_room_aide())) {
578 assoc_file_name(CC->upl_path, sizeof CC->upl_path, &CC->room, ctdl_image_dir);
581 if (IsEmptyStr(CC->upl_path)) {
582 cprintf("%d Higher access required.\n",
583 ERROR + HIGHER_ACCESS_REQUIRED);
587 if (is_this_for_real == 0) {
588 cprintf("%d Ok to send image\n", CIT_OK);
592 CC->upload_fp = fopen(CC->upl_path, "wb");
593 if (CC->upload_fp == NULL) {
594 cprintf("%d Cannot open %s: %s\n",
595 ERROR + INTERNAL_ERROR, CC->upl_path, strerror(errno));
598 cprintf("%d Ok\n", CIT_OK);
599 CC->upload_type = UPL_IMAGE;
604 * close the download file
610 if (CC->download_fp == NULL) {
611 cprintf("%d You don't have a download file open.\n",
612 ERROR + RESOURCE_NOT_OPEN);
616 fclose(CC->download_fp);
617 CC->download_fp = NULL;
619 if (CC->dl_is_net == 1) {
621 snprintf(buf, sizeof buf,
628 cprintf("%d Ok\n", CIT_OK);
635 void abort_upl(struct CitContext *who)
637 if (who->upload_fp != NULL) {
638 fclose(who->upload_fp);
639 who->upload_fp = NULL;
640 unlink(CC->upl_path);
647 * close the upload file
649 void cmd_ucls(char *cmd)
652 char upload_notice[512];
654 if (CC->upload_fp == NULL) {
655 cprintf("%d You don't have an upload file open.\n", ERROR + RESOURCE_NOT_OPEN);
659 fclose(CC->upload_fp);
660 CC->upload_fp = NULL;
662 if ((!strcasecmp(cmd, "1")) && (CC->upload_type != UPL_FILE)) {
663 CC->upload_type = UPL_FILE;
664 cprintf("%d Upload completed.\n", CIT_OK);
666 /* FIXME ... here we need to trigger a network run */
671 if (!strcasecmp(cmd, "1")) {
672 cprintf("%d File '%s' saved.\n", CIT_OK, CC->upl_path);
673 fp = fopen(CC->upl_filedir, "a");
675 fp = fopen(CC->upl_filedir, "w");
678 fprintf(fp, "%s %s\n", CC->upl_file,
683 /* put together an upload notice */
684 snprintf(upload_notice, sizeof upload_notice,
685 "NEW UPLOAD: '%s'\n %s\n",
686 CC->upl_file, CC->upl_comment);
687 quickie_message(CC->curr_user, NULL, NULL, CC->room.QRname,
688 upload_notice, 0, NULL);
691 cprintf("%d File '%s' aborted.\n", CIT_OK, CC->upl_path);
698 * read from the download file
700 void cmd_read(char *cmdbuf)
707 start_pos = extract_long(cmdbuf, 0);
708 bytes = extract_int(cmdbuf, 1);
710 if (CC->download_fp == NULL) {
711 cprintf("%d You don't have a download file open.\n",
712 ERROR + RESOURCE_NOT_OPEN);
716 if (bytes > 100000) bytes = 100000;
717 buf = malloc(bytes + 1);
719 fseek(CC->download_fp, start_pos, 0);
720 actual_bytes = fread(buf, 1, bytes, CC->download_fp);
721 cprintf("%d %d\n", BINARY_FOLLOWS, (int)actual_bytes);
722 client_write(buf, actual_bytes);
729 * write to the upload file
731 void cmd_writ(char *cmdbuf)
738 bytes = extract_int(cmdbuf, 0);
740 if (CC->upload_fp == NULL) {
741 cprintf("%d You don't have an upload file open.\n", ERROR + RESOURCE_NOT_OPEN);
745 if (bytes > 100000) {
746 cprintf("%d You may not write more than 100000 bytes.\n",
751 cprintf("%d %d\n", SEND_BINARY, bytes);
752 buf = malloc(bytes + 1);
753 client_read(buf, bytes);
754 fwrite(buf, bytes, 1, CC->upload_fp);
762 * cmd_ndop() - open a network spool file for downloading
764 void cmd_ndop(char *cmdbuf)
769 if (IsEmptyStr(CC->net_node)) {
770 cprintf("%d Not authenticated as a network node.\n",
771 ERROR + NOT_LOGGED_IN);
775 if (CC->download_fp != NULL) {
776 cprintf("%d You already have a download file open.\n",
777 ERROR + RESOURCE_BUSY);
781 snprintf(pathname, sizeof pathname,
786 /* first open the file in append mode in order to create a
787 * zero-length file if it doesn't already exist
789 CC->download_fp = fopen(pathname, "a");
790 if (CC->download_fp != NULL)
791 fclose(CC->download_fp);
794 CC->download_fp = fopen(pathname, "r");
795 if (CC->download_fp == NULL) {
796 cprintf("%d cannot open %s: %s\n",
797 ERROR + INTERNAL_ERROR, pathname, strerror(errno));
802 /* set this flag so other routines know that the download file
803 * currently open is a network spool file
807 stat(pathname, &statbuf);
808 cprintf("%d %ld\n", CIT_OK, (long)statbuf.st_size);
812 * cmd_nuop() - open a network spool file for uploading
814 void cmd_nuop(char *cmdbuf)
818 if (IsEmptyStr(CC->net_node)) {
819 cprintf("%d Not authenticated as a network node.\n",
820 ERROR + NOT_LOGGED_IN);
824 if (CC->upload_fp != NULL) {
825 cprintf("%d You already have an upload file open.\n",
826 ERROR + RESOURCE_BUSY);
830 snprintf(CC->upl_path, sizeof CC->upl_path,
837 CC->upload_fp = fopen(CC->upl_path, "r");
838 if (CC->upload_fp != NULL) {
839 fclose(CC->upload_fp);
840 CC->upload_fp = NULL;
841 cprintf("%d '%s' already exists\n",
842 ERROR + ALREADY_EXISTS, CC->upl_path);
846 CC->upload_fp = fopen(CC->upl_path, "w");
847 if (CC->upload_fp == NULL) {
848 cprintf("%d Cannot open %s: %s\n",
849 ERROR + INTERNAL_ERROR, CC->upl_path, strerror(errno));
853 CC->upload_type = UPL_NET;
854 cprintf("%d Ok\n", CIT_OK);