4 * Server functions which handle file transfers and room directories.
22 #if TIME_WITH_SYS_TIME
23 # include <sys/time.h>
27 # include <sys/time.h>
36 #include "dynloader.h"
39 #include "sysdep_decls.h"
45 #include "citserver.h"
49 * network_talking_to() -- concurrency checker
51 int network_talking_to(char *nodename, int operation) {
53 static char *nttlist = NULL;
59 begin_critical_section(S_NTTLIST);
64 if (nttlist == NULL) nttlist = strdoop("");
65 if (nttlist == NULL) break;
66 nttlist = (char *)reallok(nttlist,
67 (strlen(nttlist) + strlen(nodename) + 3) );
69 strcat(nttlist, nodename);
73 if (nttlist == NULL) break;
74 if (strlen(nttlist) == 0) break;
75 ptr = mallok(strlen(nttlist));
76 if (ptr == NULL) break;
78 for (i = 0; i < num_tokens(nttlist, '|'); ++i) {
79 extract(buf, nttlist, i);
80 if ( (strlen(buf) > 0)
81 && (strcasecmp(buf, nodename)) ) {
91 if (nttlist == NULL) break;
92 if (strlen(nttlist) == 0) break;
93 for (i = 0; i < num_tokens(nttlist, '|'); ++i) {
94 extract(buf, nttlist, i);
95 if (!strcasecmp(buf, nodename)) ++retval;
100 if (nttlist != NULL) lprintf(9, "nttlist=<%s>\n", nttlist);
101 end_critical_section(S_NTTLIST);
109 * Server command to delete a file from a room's directory
111 void cmd_delf(char *filename)
116 if (CtdlAccessCheck(ac_room_aide))
119 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
120 cprintf("%d No directory in this room.\n",
125 if (strlen(filename) == 0) {
126 cprintf("%d You must specify a file name.\n",
127 ERROR + FILE_NOT_FOUND);
130 for (a = 0; a < strlen(filename); ++a) {
131 if (filename[a] == '/') {
135 snprintf(pathname, sizeof pathname, "./files/%s/%s",
136 CC->quickroom.QRdirname, filename);
137 a = unlink(pathname);
139 cprintf("%d File '%s' deleted.\n", OK, pathname);
142 cprintf("%d File '%s' not found.\n",
143 ERROR + FILE_NOT_FOUND, pathname);
151 * move a file from one room directory to another
153 void cmd_movf(char *cmdbuf)
161 struct quickroom qrbuf;
163 extract(filename, cmdbuf, 0);
164 extract(newroom, cmdbuf, 1);
166 if (CtdlAccessCheck(ac_room_aide)) return;
168 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
169 cprintf("%d No directory in this room.\n",
174 if (strlen(filename) == 0) {
175 cprintf("%d You must specify a file name.\n",
176 ERROR + FILE_NOT_FOUND);
180 for (a = 0; a < strlen(filename); ++a) {
181 if (filename[a] == '/') {
185 snprintf(pathname, sizeof pathname, "./files/%s/%s",
186 CC->quickroom.QRdirname, filename);
187 if (access(pathname, 0) != 0) {
188 cprintf("%d File '%s' not found.\n",
189 ERROR + FILE_NOT_FOUND, pathname);
193 if (getroom(&qrbuf, newroom) != 0) {
194 cprintf("%d '%s' does not exist.\n", ERROR, newroom);
197 if ((qrbuf.QRflags & QR_DIRECTORY) == 0) {
198 cprintf("%d '%s' is not a directory room.\n",
199 ERROR + NOT_HERE, qrbuf.QRname);
202 snprintf(newpath, sizeof newpath, "./files/%s/%s", qrbuf.QRdirname,
204 if (link(pathname, newpath) != 0) {
205 cprintf("%d Couldn't move file: %s\n", ERROR,
211 /* this is a crude method of copying the file description */
212 snprintf(buf, sizeof buf,
213 "cat ./files/%s/filedir |grep %s >>./files/%s/filedir",
214 CC->quickroom.QRdirname, filename, qrbuf.QRdirname);
216 cprintf("%d File '%s' has been moved.\n", OK, filename);
221 * send a file over the net
223 void cmd_netf(char *cmdbuf)
225 char pathname[SIZ], filename[SIZ], destsys[SIZ], buf[SIZ];
232 extract(filename, cmdbuf, 0);
233 extract(destsys, cmdbuf, 1);
235 if (CtdlAccessCheck(ac_room_aide)) return;
237 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
238 cprintf("%d No directory in this room.\n",
243 if (strlen(filename) == 0) {
244 cprintf("%d You must specify a file name.\n",
245 ERROR + FILE_NOT_FOUND);
249 for (a = 0; a < strlen(filename); ++a) {
250 if (filename[a] == '/') {
254 snprintf(pathname, sizeof pathname, "./files/%s/%s",
255 CC->quickroom.QRdirname, filename);
256 if (access(pathname, 0) != 0) {
257 cprintf("%d File '%s' not found.\n",
258 ERROR + FILE_NOT_FOUND, pathname);
261 snprintf(buf, sizeof buf, "sysop@%s", destsys);
263 if (e != MES_BINARY) {
264 cprintf("%d No such system: '%s'\n",
265 ERROR + NO_SUCH_SYSTEM, destsys);
268 snprintf(outfile, sizeof outfile,
269 "%s/network/spoolin/nsf.%04x.%04x",
270 BBSDIR, getpid(), ++seq);
271 ofp = fopen(outfile, "a");
273 cprintf("%d internal error\n", ERROR);
278 putc(MES_NORMAL, ofp);
280 fprintf(ofp, "Pcit%ld", CC->usersupp.usernum);
283 fprintf(ofp, "T%ld", (long) now);
285 fprintf(ofp, "A%s", CC->usersupp.fullname);
287 fprintf(ofp, "O%s", CC->quickroom.QRname);
289 fprintf(ofp, "N%s", NODENAME);
291 fprintf(ofp, "D%s", destsys);
293 fprintf(ofp, "SFILE");
298 snprintf(buf, sizeof buf,
299 "cd ./files/%s; uuencode %s <%s 2>/dev/null >>%s",
300 CC->quickroom.QRdirname, filename, filename, outfile);
303 ofp = fopen(outfile, "a");
307 cprintf("%d File '%s' has been sent to %s.\n", OK, filename,
309 /* FIXME start a network run here. */
314 * This code is common to all commands which open a file for downloading,
315 * regardless of whether it's a file from the directory, an image, a network
316 * spool file, a MIME attachment, etc.
317 * It examines the file and displays the OK result code and some information
318 * about the file. NOTE: this stuff is Unix dependent.
320 void OpenCmdResult(char *filename, char *mime_type)
326 fstat(fileno(CC->download_fp), &statbuf);
327 filesize = (long) statbuf.st_size;
328 modtime = (time_t) statbuf.st_mtime;
330 cprintf("%d %ld|%ld|%s|%s\n",
331 OK, filesize, modtime, filename, mime_type);
336 * open a file for downloading
338 void cmd_open(char *cmdbuf)
344 extract(filename, cmdbuf, 0);
346 if (CtdlAccessCheck(ac_logged_in)) return;
348 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
349 cprintf("%d No directory in this room.\n",
354 if (strlen(filename) == 0) {
355 cprintf("%d You must specify a file name.\n",
356 ERROR + FILE_NOT_FOUND);
360 if (CC->download_fp != NULL) {
361 cprintf("%d You already have a download file open.\n",
366 for (a = 0; a < strlen(filename); ++a) {
367 if (filename[a] == '/') {
372 snprintf(pathname, sizeof pathname,
373 "./files/%s/%s", CC->quickroom.QRdirname, filename);
374 CC->download_fp = fopen(pathname, "r");
376 if (CC->download_fp == NULL) {
377 cprintf("%d cannot open %s: %s\n",
378 ERROR, pathname, strerror(errno));
382 OpenCmdResult(filename, "application/octet-stream");
388 void cmd_oimg(char *cmdbuf)
392 struct usersupp usbuf;
397 extract(filename, cmdbuf, 0);
399 if (strlen(filename) == 0) {
400 cprintf("%d You must specify a file name.\n",
401 ERROR + FILE_NOT_FOUND);
405 if (CC->download_fp != NULL) {
406 cprintf("%d You already have a download file open.\n",
411 if (!strcasecmp(filename, "_userpic_")) {
412 extract(which_user, cmdbuf, 1);
413 if (getuser(&usbuf, which_user) != 0) {
414 cprintf("%d No such user.\n",
415 ERROR + NO_SUCH_USER);
418 snprintf(pathname, sizeof pathname, "./userpics/%ld.gif",
420 } else if (!strcasecmp(filename, "_floorpic_")) {
421 which_floor = extract_int(cmdbuf, 1);
422 snprintf(pathname, sizeof pathname,
423 "./images/floor.%d.gif", which_floor);
424 } else if (!strcasecmp(filename, "_roompic_")) {
425 assoc_file_name(pathname, &CC->quickroom, "images");
427 for (a = 0; a < strlen(filename); ++a) {
428 filename[a] = tolower(filename[a]);
429 if (filename[a] == '/') {
433 snprintf(pathname, sizeof pathname, "./images/%s.gif",
437 CC->download_fp = fopen(pathname, "rb");
438 if (CC->download_fp == NULL) {
439 cprintf("%d Cannot open %s: %s\n",
440 ERROR + FILE_NOT_FOUND, pathname, strerror(errno));
444 OpenCmdResult(pathname, "image/gif");
448 * open a file for uploading
450 void cmd_uopn(char *cmdbuf)
454 extract(CC->upl_file, cmdbuf, 0);
455 extract(CC->upl_comment, cmdbuf, 1);
457 if (CtdlAccessCheck(ac_logged_in)) return;
459 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
460 cprintf("%d No directory in this room.\n",
465 if (strlen(CC->upl_file) == 0) {
466 cprintf("%d You must specify a file name.\n",
467 ERROR + FILE_NOT_FOUND);
471 if (CC->upload_fp != NULL) {
472 cprintf("%d You already have a upload file open.\n",
477 for (a = 0; a < strlen(CC->upl_file); ++a) {
478 if (CC->upl_file[a] == '/') {
479 CC->upl_file[a] = '_';
482 snprintf(CC->upl_path, sizeof CC->upl_path, "./files/%s/%s",
483 CC->quickroom.QRdirname, CC->upl_file);
484 snprintf(CC->upl_filedir, sizeof CC->upl_filedir,
485 "./files/%s/filedir", CC->quickroom.QRdirname);
487 CC->upload_fp = fopen(CC->upl_path, "r");
488 if (CC->upload_fp != NULL) {
489 fclose(CC->upload_fp);
490 CC->upload_fp = NULL;
491 cprintf("%d '%s' already exists\n",
492 ERROR + ALREADY_EXISTS, CC->upl_path);
496 CC->upload_fp = fopen(CC->upl_path, "wb");
497 if (CC->upload_fp == NULL) {
498 cprintf("%d Cannot open %s: %s\n",
499 ERROR, CC->upl_path, strerror(errno));
502 cprintf("%d Ok\n", OK);
508 * open an image file for uploading
510 void cmd_uimg(char *cmdbuf)
512 int is_this_for_real;
517 if (num_parms(cmdbuf) < 2) {
518 cprintf("%d Usage error.\n", ERROR);
522 is_this_for_real = extract_int(cmdbuf, 0);
523 extract(basenm, cmdbuf, 1);
524 if (CC->upload_fp != NULL) {
525 cprintf("%d You already have an upload file open.\n",
530 strcpy(CC->upl_path, "");
532 for (a = 0; a < strlen(basenm); ++a) {
533 basenm[a] = tolower(basenm[a]);
534 if (basenm[a] == '/') {
539 if (CC->usersupp.axlevel >= 6) {
540 snprintf(CC->upl_path, sizeof CC->upl_path, "./images/%s",
544 if (!strcasecmp(basenm, "_userpic_")) {
545 snprintf(CC->upl_path, sizeof CC->upl_path,
546 "./userpics/%ld.gif", CC->usersupp.usernum);
549 if ((!strcasecmp(basenm, "_floorpic_"))
550 && (CC->usersupp.axlevel >= 6)) {
551 which_floor = extract_int(cmdbuf, 2);
552 snprintf(CC->upl_path, sizeof CC->upl_path,
553 "./images/floor.%d.gif", which_floor);
556 if ((!strcasecmp(basenm, "_roompic_")) && (is_room_aide())) {
557 assoc_file_name(CC->upl_path, &CC->quickroom, "images");
560 if (strlen(CC->upl_path) == 0) {
561 cprintf("%d Higher access required.\n",
562 ERROR + HIGHER_ACCESS_REQUIRED);
566 if (is_this_for_real == 0) {
567 cprintf("%d Ok to send image\n", OK);
571 CC->upload_fp = fopen(CC->upl_path, "wb");
572 if (CC->upload_fp == NULL) {
573 cprintf("%d Cannot open %s: %s\n",
574 ERROR, CC->upl_path, strerror(errno));
577 cprintf("%d Ok\n", OK);
578 CC->upload_type = UPL_IMAGE;
583 * close the download file
589 if (CC->download_fp == NULL) {
590 cprintf("%d You don't have a download file open.\n",
595 fclose(CC->download_fp);
596 CC->download_fp = NULL;
598 if (CC->dl_is_net == 1) {
600 snprintf(buf, sizeof buf, "%s/network/spoolout/%s", BBSDIR,
605 cprintf("%d Ok\n", OK);
612 void abort_upl(struct CitContext *who)
614 if (who->upload_fp != NULL) {
615 fclose(who->upload_fp);
616 who->upload_fp = NULL;
617 unlink(CC->upl_path);
624 * close the upload file
626 void cmd_ucls(char *cmd)
629 char upload_notice[512];
631 if (CC->upload_fp == NULL) {
632 cprintf("%d You don't have an upload file open.\n", ERROR);
636 fclose(CC->upload_fp);
637 CC->upload_fp = NULL;
639 if ((!strcasecmp(cmd, "1")) && (CC->upload_type != UPL_FILE)) {
640 CC->upload_type = UPL_FILE;
641 cprintf("%d Upload completed.\n", OK);
643 /* FIXME ... here we need to trigger a network run */
648 if (!strcasecmp(cmd, "1")) {
649 cprintf("%d File '%s' saved.\n", OK, CC->upl_path);
650 fp = fopen(CC->upl_filedir, "a");
652 fp = fopen(CC->upl_filedir, "w");
655 fprintf(fp, "%s %s\n", CC->upl_file,
660 /* put together an upload notice */
661 sprintf(upload_notice,
662 "NEW UPLOAD: '%s'\n %s\n",
663 CC->upl_file, CC->upl_comment);
664 quickie_message(CC->curr_user, NULL, CC->quickroom.QRname,
668 cprintf("%d File '%s' aborted.\n", OK, CC->upl_path);
675 * read from the download file
677 void cmd_read(char *cmdbuf)
683 start_pos = extract_long(cmdbuf, 0);
684 bytes = extract_int(cmdbuf, 1);
686 if (CC->download_fp == NULL) {
687 cprintf("%d You don't have a download file open.\n",
693 cprintf("%d You may not read more than 4096 bytes.\n",
698 fseek(CC->download_fp, start_pos, 0);
699 fread(buf, bytes, 1, CC->download_fp);
700 cprintf("%d %d\n", BINARY_FOLLOWS, bytes);
701 client_write(buf, bytes);
707 * write to the upload file
709 void cmd_writ(char *cmdbuf)
714 bytes = extract_int(cmdbuf, 0);
716 if (CC->upload_fp == NULL) {
717 cprintf("%d You don't have an upload file open.\n", ERROR);
722 cprintf("%d You may not write more than 4096 bytes.\n",
727 cprintf("%d %d\n", SEND_BINARY, bytes);
728 client_read(buf, bytes);
729 fwrite(buf, bytes, 1, CC->upload_fp);
736 * cmd_ndop() - open a network spool file for downloading
738 void cmd_ndop(char *cmdbuf)
743 if (strlen(CC->net_node) == 0) {
744 cprintf("%d Not authenticated as a network node.\n",
745 ERROR + NOT_LOGGED_IN);
749 if (CC->download_fp != NULL) {
750 cprintf("%d You already have a download file open.\n",
755 snprintf(pathname, sizeof pathname, "%s/network/spoolout/%s",
756 BBSDIR, CC->net_node);
758 /* first open the file in append mode in order to create a
759 * zero-length file if it doesn't already exist
761 CC->download_fp = fopen(pathname, "a");
762 if (CC->download_fp != NULL)
763 fclose(CC->download_fp);
766 CC->download_fp = fopen(pathname, "r");
767 if (CC->download_fp == NULL) {
768 cprintf("%d cannot open %s: %s\n",
769 ERROR, pathname, strerror(errno));
774 /* set this flag so other routines know that the download file
775 * currently open is a network spool file
779 stat(pathname, &statbuf);
780 cprintf("%d %ld\n", OK, statbuf.st_size);
784 * cmd_nuop() - open a network spool file for uploading
786 void cmd_nuop(char *cmdbuf)
790 if (strlen(CC->net_node) == 0) {
791 cprintf("%d Not authenticated as a network node.\n",
792 ERROR + NOT_LOGGED_IN);
796 if (CC->upload_fp != NULL) {
797 cprintf("%d You already have an upload file open.\n",
802 snprintf(CC->upl_path, sizeof CC->upl_path,
803 "%s/network/spoolin/%s.%04x.%04x",
804 BBSDIR, CC->net_node, getpid(), ++seq);
806 CC->upload_fp = fopen(CC->upl_path, "r");
807 if (CC->upload_fp != NULL) {
808 fclose(CC->upload_fp);
809 CC->upload_fp = NULL;
810 cprintf("%d '%s' already exists\n",
811 ERROR + ALREADY_EXISTS, CC->upl_path);
815 CC->upload_fp = fopen(CC->upl_path, "w");
816 if (CC->upload_fp == NULL) {
817 cprintf("%d Cannot open %s: %s\n",
818 ERROR, CC->upl_path, strerror(errno));
822 CC->upload_type = UPL_NET;
823 cprintf("%d Ok\n", OK);