4 * Server functions which handle file transfers and room directories.
23 #if TIME_WITH_SYS_TIME
24 # include <sys/time.h>
28 # include <sys/time.h>
37 #include "serv_extensions.h"
40 #include "sysdep_decls.h"
46 #include "citserver.h"
53 * network_talking_to() -- concurrency checker
55 int network_talking_to(char *nodename, int operation) {
57 static char *nttlist = NULL;
63 begin_critical_section(S_NTTLIST);
68 if (nttlist == NULL) nttlist = strdup("");
69 if (nttlist == NULL) break;
70 nttlist = (char *)realloc(nttlist,
71 (strlen(nttlist) + strlen(nodename) + 3) );
73 strcat(nttlist, nodename);
77 if (nttlist == NULL) break;
78 if (strlen(nttlist) == 0) break;
79 ptr = malloc(strlen(nttlist));
80 if (ptr == NULL) break;
82 for (i = 0; i < num_tokens(nttlist, '|'); ++i) {
83 extract_token(buf, nttlist, i, '|', sizeof buf);
84 if ( (strlen(buf) > 0)
85 && (strcasecmp(buf, nodename)) ) {
95 if (nttlist == NULL) break;
96 if (strlen(nttlist) == 0) break;
97 for (i = 0; i < num_tokens(nttlist, '|'); ++i) {
98 extract_token(buf, nttlist, i, '|', sizeof buf);
99 if (!strcasecmp(buf, nodename)) ++retval;
104 if (nttlist != NULL) lprintf(CTDL_DEBUG, "nttlist=<%s>\n", nttlist);
105 end_critical_section(S_NTTLIST);
113 * Server command to delete a file from a room's directory
115 void cmd_delf(char *filename)
120 if (CtdlAccessCheck(ac_room_aide))
123 if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
124 cprintf("%d No directory in this room.\n",
129 if (strlen(filename) == 0) {
130 cprintf("%d You must specify a file name.\n",
131 ERROR + FILE_NOT_FOUND);
134 for (a = 0; a < strlen(filename); ++a) {
135 if (filename[a] == '/') {
139 snprintf(pathname, sizeof pathname, "./files/%s/%s",
140 CC->room.QRdirname, filename);
141 a = unlink(pathname);
143 cprintf("%d File '%s' deleted.\n", CIT_OK, pathname);
146 cprintf("%d File '%s' not found.\n",
147 ERROR + FILE_NOT_FOUND, pathname);
155 * move a file from one room directory to another
157 void cmd_movf(char *cmdbuf)
159 char filename[PATH_MAX];
160 char pathname[PATH_MAX];
161 char newpath[PATH_MAX];
162 char newroom[ROOMNAMELEN];
165 struct ctdlroom qrbuf;
167 extract_token(filename, cmdbuf, 0, '|', sizeof filename);
168 extract_token(newroom, cmdbuf, 1, '|', sizeof newroom);
170 if (CtdlAccessCheck(ac_room_aide)) return;
172 if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
173 cprintf("%d No directory in this room.\n",
178 if (strlen(filename) == 0) {
179 cprintf("%d You must specify a file name.\n",
180 ERROR + FILE_NOT_FOUND);
184 for (a = 0; a < strlen(filename); ++a) {
185 if (filename[a] == '/') {
189 snprintf(pathname, sizeof pathname, "./files/%s/%s",
190 CC->room.QRdirname, filename);
191 if (access(pathname, 0) != 0) {
192 cprintf("%d File '%s' not found.\n",
193 ERROR + FILE_NOT_FOUND, pathname);
197 if (getroom(&qrbuf, newroom) != 0) {
198 cprintf("%d '%s' does not exist.\n", ERROR + ROOM_NOT_FOUND, newroom);
201 if ((qrbuf.QRflags & QR_DIRECTORY) == 0) {
202 cprintf("%d '%s' is not a directory room.\n",
203 ERROR + NOT_HERE, qrbuf.QRname);
206 snprintf(newpath, sizeof newpath, "./files/%s/%s", qrbuf.QRdirname,
208 if (link(pathname, newpath) != 0) {
209 cprintf("%d Couldn't move file: %s\n", ERROR + INTERNAL_ERROR,
215 /* this is a crude method of copying the file description */
216 snprintf(buf, sizeof buf,
217 "cat ./files/%s/filedir |grep %s >>./files/%s/filedir",
218 CC->room.QRdirname, filename, qrbuf.QRdirname);
220 cprintf("%d File '%s' has been moved.\n", CIT_OK, filename);
225 * send a file over the net
227 void cmd_netf(char *cmdbuf)
229 char pathname[256], filename[256], destsys[256], buf[256];
236 extract_token(filename, cmdbuf, 0, '|', sizeof filename);
237 extract_token(destsys, cmdbuf, 1, '|', sizeof destsys);
239 if (CtdlAccessCheck(ac_room_aide)) return;
241 if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
242 cprintf("%d No directory in this room.\n",
247 if (strlen(filename) == 0) {
248 cprintf("%d You must specify a file name.\n",
249 ERROR + FILE_NOT_FOUND);
253 for (a = 0; a < strlen(filename); ++a) {
254 if (filename[a] == '/') {
258 snprintf(pathname, sizeof pathname, "./files/%s/%s",
259 CC->room.QRdirname, filename);
260 if (access(pathname, 0) != 0) {
261 cprintf("%d File '%s' not found.\n",
262 ERROR + FILE_NOT_FOUND, pathname);
265 snprintf(buf, sizeof buf, "sysop@%s", destsys);
267 if (e != MES_IGNET) {
268 cprintf("%d No such system: '%s'\n",
269 ERROR + NO_SUCH_SYSTEM, destsys);
272 snprintf(outfile, sizeof outfile,
273 "%s/network/spoolin/nsf.%04lx.%04x",
274 BBSDIR, (long)getpid(), ++seq);
275 ofp = fopen(outfile, "a");
277 cprintf("%d internal error\n", ERROR + INTERNAL_ERROR);
282 putc(MES_NORMAL, ofp);
284 fprintf(ofp, "Pcit%ld", CC->user.usernum);
287 fprintf(ofp, "T%ld", (long) now);
289 fprintf(ofp, "A%s", CC->user.fullname);
291 fprintf(ofp, "O%s", CC->room.QRname);
293 fprintf(ofp, "N%s", NODENAME);
295 fprintf(ofp, "D%s", destsys);
297 fprintf(ofp, "SFILE");
302 snprintf(buf, sizeof buf,
303 "cd ./files/%s; uuencode %s <%s 2>/dev/null >>%s",
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 (strlen(filename) == 0) {
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; a < strlen(filename); ++a) {
371 if (filename[a] == '/') {
376 snprintf(pathname, sizeof pathname,
377 "./files/%s/%s", CC->room.QRdirname, filename);
378 CC->download_fp = fopen(pathname, "r");
380 if (CC->download_fp == NULL) {
381 cprintf("%d cannot open %s: %s\n",
382 ERROR + INTERNAL_ERROR, pathname, strerror(errno));
386 OpenCmdResult(filename, "application/octet-stream");
392 void cmd_oimg(char *cmdbuf)
395 char pathname[PATH_MAX];
396 struct ctdluser usbuf;
397 char which_user[USERNAME_SIZE];
401 extract_token(filename, cmdbuf, 0, '|', sizeof filename);
403 if (strlen(filename) == 0) {
404 cprintf("%d You must specify a file name.\n",
405 ERROR + FILE_NOT_FOUND);
409 if (CC->download_fp != NULL) {
410 cprintf("%d You already have a download file open.\n",
411 ERROR + RESOURCE_BUSY);
415 if (!strcasecmp(filename, "_userpic_")) {
416 extract_token(which_user, cmdbuf, 1, '|', sizeof which_user);
417 if (getuser(&usbuf, which_user) != 0) {
418 cprintf("%d No such user.\n",
419 ERROR + NO_SUCH_USER);
422 snprintf(pathname, sizeof pathname, "./userpics/%ld.gif",
424 } else if (!strcasecmp(filename, "_floorpic_")) {
425 which_floor = extract_int(cmdbuf, 1);
426 snprintf(pathname, sizeof pathname,
427 "./images/floor.%d.gif", which_floor);
428 } else if (!strcasecmp(filename, "_roompic_")) {
429 assoc_file_name(pathname, sizeof pathname, &CC->room, "images");
431 for (a = 0; a < strlen(filename); ++a) {
432 filename[a] = tolower(filename[a]);
433 if (filename[a] == '/') {
437 snprintf(pathname, sizeof pathname, "./images/%s.gif",
441 CC->download_fp = fopen(pathname, "rb");
442 if (CC->download_fp == NULL) {
443 cprintf("%d Cannot open %s: %s\n",
444 ERROR + FILE_NOT_FOUND, pathname, strerror(errno));
448 OpenCmdResult(pathname, "image/gif");
452 * open a file for uploading
454 void cmd_uopn(char *cmdbuf)
458 extract_token(CC->upl_file, cmdbuf, 0, '|', sizeof CC->upl_file);
459 extract_token(CC->upl_comment, cmdbuf, 1, '|', sizeof CC->upl_comment);
461 if (CtdlAccessCheck(ac_logged_in)) return;
463 if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
464 cprintf("%d No directory in this room.\n",
469 if (strlen(CC->upl_file) == 0) {
470 cprintf("%d You must specify a file name.\n",
471 ERROR + FILE_NOT_FOUND);
475 if (CC->upload_fp != NULL) {
476 cprintf("%d You already have a upload file open.\n",
477 ERROR + RESOURCE_BUSY);
481 for (a = 0; a < strlen(CC->upl_file); ++a) {
482 if (CC->upl_file[a] == '/') {
483 CC->upl_file[a] = '_';
486 snprintf(CC->upl_path, sizeof CC->upl_path, "./files/%s/%s",
487 CC->room.QRdirname, CC->upl_file);
488 snprintf(CC->upl_filedir, sizeof CC->upl_filedir,
489 "./files/%s/filedir", CC->room.QRdirname);
491 CC->upload_fp = fopen(CC->upl_path, "r");
492 if (CC->upload_fp != NULL) {
493 fclose(CC->upload_fp);
494 CC->upload_fp = NULL;
495 cprintf("%d '%s' already exists\n",
496 ERROR + ALREADY_EXISTS, CC->upl_path);
500 CC->upload_fp = fopen(CC->upl_path, "wb");
501 if (CC->upload_fp == NULL) {
502 cprintf("%d Cannot open %s: %s\n",
503 ERROR + INTERNAL_ERROR, CC->upl_path, strerror(errno));
506 cprintf("%d Ok\n", CIT_OK);
512 * open an image file for uploading
514 void cmd_uimg(char *cmdbuf)
516 int is_this_for_real;
521 if (num_parms(cmdbuf) < 2) {
522 cprintf("%d Usage error.\n", ERROR + ILLEGAL_VALUE);
526 is_this_for_real = extract_int(cmdbuf, 0);
527 extract_token(basenm, cmdbuf, 1, '|', sizeof basenm);
528 if (CC->upload_fp != NULL) {
529 cprintf("%d You already have an upload file open.\n",
530 ERROR + RESOURCE_BUSY);
534 strcpy(CC->upl_path, "");
536 for (a = 0; a < strlen(basenm); ++a) {
537 basenm[a] = tolower(basenm[a]);
538 if (basenm[a] == '/') {
543 if (CC->user.axlevel >= 6) {
544 snprintf(CC->upl_path, sizeof CC->upl_path, "./images/%s",
548 if (!strcasecmp(basenm, "_userpic_")) {
549 snprintf(CC->upl_path, sizeof CC->upl_path,
550 "./userpics/%ld.gif", CC->user.usernum);
553 if ((!strcasecmp(basenm, "_floorpic_"))
554 && (CC->user.axlevel >= 6)) {
555 which_floor = extract_int(cmdbuf, 2);
556 snprintf(CC->upl_path, sizeof CC->upl_path,
557 "./images/floor.%d.gif", which_floor);
560 if ((!strcasecmp(basenm, "_roompic_")) && (is_room_aide())) {
561 assoc_file_name(CC->upl_path, sizeof CC->upl_path, &CC->room, "images");
564 if (strlen(CC->upl_path) == 0) {
565 cprintf("%d Higher access required.\n",
566 ERROR + HIGHER_ACCESS_REQUIRED);
570 if (is_this_for_real == 0) {
571 cprintf("%d Ok to send image\n", CIT_OK);
575 CC->upload_fp = fopen(CC->upl_path, "wb");
576 if (CC->upload_fp == NULL) {
577 cprintf("%d Cannot open %s: %s\n",
578 ERROR + INTERNAL_ERROR, CC->upl_path, strerror(errno));
581 cprintf("%d Ok\n", CIT_OK);
582 CC->upload_type = UPL_IMAGE;
587 * close the download file
593 if (CC->download_fp == NULL) {
594 cprintf("%d You don't have a download file open.\n",
595 ERROR + RESOURCE_NOT_OPEN);
599 fclose(CC->download_fp);
600 CC->download_fp = NULL;
602 if (CC->dl_is_net == 1) {
604 snprintf(buf, sizeof buf, "%s/network/spoolout/%s", BBSDIR,
609 cprintf("%d Ok\n", CIT_OK);
616 void abort_upl(struct CitContext *who)
618 if (who->upload_fp != NULL) {
619 fclose(who->upload_fp);
620 who->upload_fp = NULL;
621 unlink(CC->upl_path);
628 * close the upload file
630 void cmd_ucls(char *cmd)
633 char upload_notice[512];
635 if (CC->upload_fp == NULL) {
636 cprintf("%d You don't have an upload file open.\n", ERROR + RESOURCE_NOT_OPEN);
640 fclose(CC->upload_fp);
641 CC->upload_fp = NULL;
643 if ((!strcasecmp(cmd, "1")) && (CC->upload_type != UPL_FILE)) {
644 CC->upload_type = UPL_FILE;
645 cprintf("%d Upload completed.\n", CIT_OK);
647 /* FIXME ... here we need to trigger a network run */
652 if (!strcasecmp(cmd, "1")) {
653 cprintf("%d File '%s' saved.\n", CIT_OK, CC->upl_path);
654 fp = fopen(CC->upl_filedir, "a");
656 fp = fopen(CC->upl_filedir, "w");
659 fprintf(fp, "%s %s\n", CC->upl_file,
664 /* put together an upload notice */
665 snprintf(upload_notice, sizeof upload_notice,
666 "NEW UPLOAD: '%s'\n %s\n",
667 CC->upl_file, CC->upl_comment);
668 quickie_message(CC->curr_user, NULL, CC->room.QRname,
669 upload_notice, 0, NULL);
672 cprintf("%d File '%s' aborted.\n", CIT_OK, CC->upl_path);
679 * read from the download file
681 void cmd_read(char *cmdbuf)
688 start_pos = extract_long(cmdbuf, 0);
689 bytes = extract_int(cmdbuf, 1);
691 if (CC->download_fp == NULL) {
692 cprintf("%d You don't have a download file open.\n",
693 ERROR + RESOURCE_NOT_OPEN);
697 if (bytes > 100000) bytes = 100000;
698 buf = malloc(bytes + 1);
700 fseek(CC->download_fp, start_pos, 0);
701 actual_bytes = fread(buf, 1, bytes, CC->download_fp);
702 cprintf("%d %d\n", BINARY_FOLLOWS, (int)actual_bytes);
703 client_write(buf, actual_bytes);
710 * write to the upload file
712 void cmd_writ(char *cmdbuf)
719 bytes = extract_int(cmdbuf, 0);
721 if (CC->upload_fp == NULL) {
722 cprintf("%d You don't have an upload file open.\n", ERROR + RESOURCE_NOT_OPEN);
726 if (bytes > 100000) {
727 cprintf("%d You may not write more than 100000 bytes.\n",
732 cprintf("%d %d\n", SEND_BINARY, bytes);
733 buf = malloc(bytes + 1);
734 client_read(buf, bytes);
735 fwrite(buf, bytes, 1, CC->upload_fp);
743 * cmd_ndop() - open a network spool file for downloading
745 void cmd_ndop(char *cmdbuf)
750 if (strlen(CC->net_node) == 0) {
751 cprintf("%d Not authenticated as a network node.\n",
752 ERROR + NOT_LOGGED_IN);
756 if (CC->download_fp != NULL) {
757 cprintf("%d You already have a download file open.\n",
758 ERROR + RESOURCE_BUSY);
762 snprintf(pathname, sizeof pathname, "%s/network/spoolout/%s",
763 BBSDIR, CC->net_node);
765 /* first open the file in append mode in order to create a
766 * zero-length file if it doesn't already exist
768 CC->download_fp = fopen(pathname, "a");
769 if (CC->download_fp != NULL)
770 fclose(CC->download_fp);
773 CC->download_fp = fopen(pathname, "r");
774 if (CC->download_fp == NULL) {
775 cprintf("%d cannot open %s: %s\n",
776 ERROR + INTERNAL_ERROR, pathname, strerror(errno));
781 /* set this flag so other routines know that the download file
782 * currently open is a network spool file
786 stat(pathname, &statbuf);
787 cprintf("%d %ld\n", CIT_OK, (long)statbuf.st_size);
791 * cmd_nuop() - open a network spool file for uploading
793 void cmd_nuop(char *cmdbuf)
797 if (strlen(CC->net_node) == 0) {
798 cprintf("%d Not authenticated as a network node.\n",
799 ERROR + NOT_LOGGED_IN);
803 if (CC->upload_fp != NULL) {
804 cprintf("%d You already have an upload file open.\n",
805 ERROR + RESOURCE_BUSY);
809 snprintf(CC->upl_path, sizeof CC->upl_path,
810 "%s/network/spoolin/%s.%04lx.%04x",
811 BBSDIR, CC->net_node, (long)getpid(), ++seq);
813 CC->upload_fp = fopen(CC->upl_path, "r");
814 if (CC->upload_fp != NULL) {
815 fclose(CC->upload_fp);
816 CC->upload_fp = NULL;
817 cprintf("%d '%s' already exists\n",
818 ERROR + ALREADY_EXISTS, CC->upl_path);
822 CC->upload_fp = fopen(CC->upl_path, "w");
823 if (CC->upload_fp == NULL) {
824 cprintf("%d Cannot open %s: %s\n",
825 ERROR + INTERNAL_ERROR, CC->upl_path, strerror(errno));
829 CC->upload_type = UPL_NET;
830 cprintf("%d Ok\n", CIT_OK);