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"
52 * network_talking_to() -- concurrency checker
54 int network_talking_to(char *nodename, int operation) {
56 static char *nttlist = NULL;
62 begin_critical_section(S_NTTLIST);
67 if (nttlist == NULL) nttlist = strdoop("");
68 if (nttlist == NULL) break;
69 nttlist = (char *)reallok(nttlist,
70 (strlen(nttlist) + strlen(nodename) + 3) );
72 strcat(nttlist, nodename);
76 if (nttlist == NULL) break;
77 if (strlen(nttlist) == 0) break;
78 ptr = mallok(strlen(nttlist));
79 if (ptr == NULL) break;
81 for (i = 0; i < num_tokens(nttlist, '|'); ++i) {
82 extract(buf, nttlist, i);
83 if ( (strlen(buf) > 0)
84 && (strcasecmp(buf, nodename)) ) {
94 if (nttlist == NULL) break;
95 if (strlen(nttlist) == 0) break;
96 for (i = 0; i < num_tokens(nttlist, '|'); ++i) {
97 extract(buf, nttlist, i);
98 if (!strcasecmp(buf, nodename)) ++retval;
103 if (nttlist != NULL) lprintf(9, "nttlist=<%s>\n", nttlist);
104 end_critical_section(S_NTTLIST);
112 * Server command to delete a file from a room's directory
114 void cmd_delf(char *filename)
119 if (CtdlAccessCheck(ac_room_aide))
122 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
123 cprintf("%d No directory in this room.\n",
128 if (strlen(filename) == 0) {
129 cprintf("%d You must specify a file name.\n",
130 ERROR + FILE_NOT_FOUND);
133 for (a = 0; a < strlen(filename); ++a) {
134 if (filename[a] == '/') {
138 snprintf(pathname, sizeof pathname, "./files/%s/%s",
139 CC->quickroom.QRdirname, filename);
140 a = unlink(pathname);
142 cprintf("%d File '%s' deleted.\n", OK, pathname);
145 cprintf("%d File '%s' not found.\n",
146 ERROR + FILE_NOT_FOUND, pathname);
154 * move a file from one room directory to another
156 void cmd_movf(char *cmdbuf)
164 struct quickroom qrbuf;
166 extract(filename, cmdbuf, 0);
167 extract(newroom, cmdbuf, 1);
169 if (CtdlAccessCheck(ac_room_aide)) return;
171 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
172 cprintf("%d No directory in this room.\n",
177 if (strlen(filename) == 0) {
178 cprintf("%d You must specify a file name.\n",
179 ERROR + FILE_NOT_FOUND);
183 for (a = 0; a < strlen(filename); ++a) {
184 if (filename[a] == '/') {
188 snprintf(pathname, sizeof pathname, "./files/%s/%s",
189 CC->quickroom.QRdirname, filename);
190 if (access(pathname, 0) != 0) {
191 cprintf("%d File '%s' not found.\n",
192 ERROR + FILE_NOT_FOUND, pathname);
196 if (getroom(&qrbuf, newroom) != 0) {
197 cprintf("%d '%s' does not exist.\n", ERROR, newroom);
200 if ((qrbuf.QRflags & QR_DIRECTORY) == 0) {
201 cprintf("%d '%s' is not a directory room.\n",
202 ERROR + NOT_HERE, qrbuf.QRname);
205 snprintf(newpath, sizeof newpath, "./files/%s/%s", qrbuf.QRdirname,
207 if (link(pathname, newpath) != 0) {
208 cprintf("%d Couldn't move file: %s\n", ERROR,
214 /* this is a crude method of copying the file description */
215 snprintf(buf, sizeof buf,
216 "cat ./files/%s/filedir |grep %s >>./files/%s/filedir",
217 CC->quickroom.QRdirname, filename, qrbuf.QRdirname);
219 cprintf("%d File '%s' has been moved.\n", OK, filename);
224 * send a file over the net
226 void cmd_netf(char *cmdbuf)
228 char pathname[SIZ], filename[SIZ], destsys[SIZ], buf[SIZ];
235 extract(filename, cmdbuf, 0);
236 extract(destsys, cmdbuf, 1);
238 if (CtdlAccessCheck(ac_room_aide)) return;
240 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
241 cprintf("%d No directory in this room.\n",
246 if (strlen(filename) == 0) {
247 cprintf("%d You must specify a file name.\n",
248 ERROR + FILE_NOT_FOUND);
252 for (a = 0; a < strlen(filename); ++a) {
253 if (filename[a] == '/') {
257 snprintf(pathname, sizeof pathname, "./files/%s/%s",
258 CC->quickroom.QRdirname, filename);
259 if (access(pathname, 0) != 0) {
260 cprintf("%d File '%s' not found.\n",
261 ERROR + FILE_NOT_FOUND, pathname);
264 snprintf(buf, sizeof buf, "sysop@%s", destsys);
266 if (e != MES_IGNET) {
267 cprintf("%d No such system: '%s'\n",
268 ERROR + NO_SUCH_SYSTEM, destsys);
271 snprintf(outfile, sizeof outfile,
272 "%s/network/spoolin/nsf.%04x.%04x",
273 BBSDIR, getpid(), ++seq);
274 ofp = fopen(outfile, "a");
276 cprintf("%d internal error\n", ERROR);
281 putc(MES_NORMAL, ofp);
283 fprintf(ofp, "Pcit%ld", CC->usersupp.usernum);
286 fprintf(ofp, "T%ld", (long) now);
288 fprintf(ofp, "A%s", CC->usersupp.fullname);
290 fprintf(ofp, "O%s", CC->quickroom.QRname);
292 fprintf(ofp, "N%s", NODENAME);
294 fprintf(ofp, "D%s", destsys);
296 fprintf(ofp, "SFILE");
301 snprintf(buf, sizeof buf,
302 "cd ./files/%s; uuencode %s <%s 2>/dev/null >>%s",
303 CC->quickroom.QRdirname, filename, filename, outfile);
306 ofp = fopen(outfile, "a");
310 cprintf("%d File '%s' has been sent to %s.\n", OK, filename,
312 /* FIXME start a network run here. */
317 * This code is common to all commands which open a file for downloading,
318 * regardless of whether it's a file from the directory, an image, a network
319 * spool file, a MIME attachment, etc.
320 * It examines the file and displays the OK result code and some information
321 * about the file. NOTE: this stuff is Unix dependent.
323 void OpenCmdResult(char *filename, char *mime_type)
329 fstat(fileno(CC->download_fp), &statbuf);
330 filesize = (long) statbuf.st_size;
331 modtime = (time_t) statbuf.st_mtime;
333 cprintf("%d %ld|%ld|%s|%s\n",
334 OK, filesize, (long)modtime, filename, mime_type);
339 * open a file for downloading
341 void cmd_open(char *cmdbuf)
347 extract(filename, cmdbuf, 0);
349 if (CtdlAccessCheck(ac_logged_in)) return;
351 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
352 cprintf("%d No directory in this room.\n",
357 if (strlen(filename) == 0) {
358 cprintf("%d You must specify a file name.\n",
359 ERROR + FILE_NOT_FOUND);
363 if (CC->download_fp != NULL) {
364 cprintf("%d You already have a download file open.\n",
369 for (a = 0; a < strlen(filename); ++a) {
370 if (filename[a] == '/') {
375 snprintf(pathname, sizeof pathname,
376 "./files/%s/%s", CC->quickroom.QRdirname, filename);
377 CC->download_fp = fopen(pathname, "r");
379 if (CC->download_fp == NULL) {
380 cprintf("%d cannot open %s: %s\n",
381 ERROR, pathname, strerror(errno));
385 OpenCmdResult(filename, "application/octet-stream");
391 void cmd_oimg(char *cmdbuf)
395 struct usersupp usbuf;
400 extract(filename, cmdbuf, 0);
402 if (strlen(filename) == 0) {
403 cprintf("%d You must specify a file name.\n",
404 ERROR + FILE_NOT_FOUND);
408 if (CC->download_fp != NULL) {
409 cprintf("%d You already have a download file open.\n",
414 if (!strcasecmp(filename, "_userpic_")) {
415 extract(which_user, cmdbuf, 1);
416 if (getuser(&usbuf, which_user) != 0) {
417 cprintf("%d No such user.\n",
418 ERROR + NO_SUCH_USER);
421 snprintf(pathname, sizeof pathname, "./userpics/%ld.gif",
423 } else if (!strcasecmp(filename, "_floorpic_")) {
424 which_floor = extract_int(cmdbuf, 1);
425 snprintf(pathname, sizeof pathname,
426 "./images/floor.%d.gif", which_floor);
427 } else if (!strcasecmp(filename, "_roompic_")) {
428 assoc_file_name(pathname, &CC->quickroom, "images");
430 for (a = 0; a < strlen(filename); ++a) {
431 filename[a] = tolower(filename[a]);
432 if (filename[a] == '/') {
436 snprintf(pathname, sizeof pathname, "./images/%s.gif",
440 CC->download_fp = fopen(pathname, "rb");
441 if (CC->download_fp == NULL) {
442 cprintf("%d Cannot open %s: %s\n",
443 ERROR + FILE_NOT_FOUND, pathname, strerror(errno));
447 OpenCmdResult(pathname, "image/gif");
451 * open a file for uploading
453 void cmd_uopn(char *cmdbuf)
457 extract(CC->upl_file, cmdbuf, 0);
458 extract(CC->upl_comment, cmdbuf, 1);
460 if (CtdlAccessCheck(ac_logged_in)) return;
462 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
463 cprintf("%d No directory in this room.\n",
468 if (strlen(CC->upl_file) == 0) {
469 cprintf("%d You must specify a file name.\n",
470 ERROR + FILE_NOT_FOUND);
474 if (CC->upload_fp != NULL) {
475 cprintf("%d You already have a upload file open.\n",
480 for (a = 0; a < strlen(CC->upl_file); ++a) {
481 if (CC->upl_file[a] == '/') {
482 CC->upl_file[a] = '_';
485 snprintf(CC->upl_path, sizeof CC->upl_path, "./files/%s/%s",
486 CC->quickroom.QRdirname, CC->upl_file);
487 snprintf(CC->upl_filedir, sizeof CC->upl_filedir,
488 "./files/%s/filedir", CC->quickroom.QRdirname);
490 CC->upload_fp = fopen(CC->upl_path, "r");
491 if (CC->upload_fp != NULL) {
492 fclose(CC->upload_fp);
493 CC->upload_fp = NULL;
494 cprintf("%d '%s' already exists\n",
495 ERROR + ALREADY_EXISTS, CC->upl_path);
499 CC->upload_fp = fopen(CC->upl_path, "wb");
500 if (CC->upload_fp == NULL) {
501 cprintf("%d Cannot open %s: %s\n",
502 ERROR, CC->upl_path, strerror(errno));
505 cprintf("%d Ok\n", OK);
511 * open an image file for uploading
513 void cmd_uimg(char *cmdbuf)
515 int is_this_for_real;
520 if (num_parms(cmdbuf) < 2) {
521 cprintf("%d Usage error.\n", ERROR);
525 is_this_for_real = extract_int(cmdbuf, 0);
526 extract(basenm, cmdbuf, 1);
527 if (CC->upload_fp != NULL) {
528 cprintf("%d You already have an upload file open.\n",
533 strcpy(CC->upl_path, "");
535 for (a = 0; a < strlen(basenm); ++a) {
536 basenm[a] = tolower(basenm[a]);
537 if (basenm[a] == '/') {
542 if (CC->usersupp.axlevel >= 6) {
543 snprintf(CC->upl_path, sizeof CC->upl_path, "./images/%s",
547 if (!strcasecmp(basenm, "_userpic_")) {
548 snprintf(CC->upl_path, sizeof CC->upl_path,
549 "./userpics/%ld.gif", CC->usersupp.usernum);
552 if ((!strcasecmp(basenm, "_floorpic_"))
553 && (CC->usersupp.axlevel >= 6)) {
554 which_floor = extract_int(cmdbuf, 2);
555 snprintf(CC->upl_path, sizeof CC->upl_path,
556 "./images/floor.%d.gif", which_floor);
559 if ((!strcasecmp(basenm, "_roompic_")) && (is_room_aide())) {
560 assoc_file_name(CC->upl_path, &CC->quickroom, "images");
563 if (strlen(CC->upl_path) == 0) {
564 cprintf("%d Higher access required.\n",
565 ERROR + HIGHER_ACCESS_REQUIRED);
569 if (is_this_for_real == 0) {
570 cprintf("%d Ok to send image\n", OK);
574 CC->upload_fp = fopen(CC->upl_path, "wb");
575 if (CC->upload_fp == NULL) {
576 cprintf("%d Cannot open %s: %s\n",
577 ERROR, CC->upl_path, strerror(errno));
580 cprintf("%d Ok\n", OK);
581 CC->upload_type = UPL_IMAGE;
586 * close the download file
592 if (CC->download_fp == NULL) {
593 cprintf("%d You don't have a download file open.\n",
598 fclose(CC->download_fp);
599 CC->download_fp = NULL;
601 if (CC->dl_is_net == 1) {
603 snprintf(buf, sizeof buf, "%s/network/spoolout/%s", BBSDIR,
608 cprintf("%d Ok\n", OK);
615 void abort_upl(struct CitContext *who)
617 if (who->upload_fp != NULL) {
618 fclose(who->upload_fp);
619 who->upload_fp = NULL;
620 unlink(CC->upl_path);
627 * close the upload file
629 void cmd_ucls(char *cmd)
632 char upload_notice[512];
634 if (CC->upload_fp == NULL) {
635 cprintf("%d You don't have an upload file open.\n", ERROR);
639 fclose(CC->upload_fp);
640 CC->upload_fp = NULL;
642 if ((!strcasecmp(cmd, "1")) && (CC->upload_type != UPL_FILE)) {
643 CC->upload_type = UPL_FILE;
644 cprintf("%d Upload completed.\n", OK);
646 /* FIXME ... here we need to trigger a network run */
651 if (!strcasecmp(cmd, "1")) {
652 cprintf("%d File '%s' saved.\n", OK, CC->upl_path);
653 fp = fopen(CC->upl_filedir, "a");
655 fp = fopen(CC->upl_filedir, "w");
658 fprintf(fp, "%s %s\n", CC->upl_file,
663 /* put together an upload notice */
664 sprintf(upload_notice,
665 "NEW UPLOAD: '%s'\n %s\n",
666 CC->upl_file, CC->upl_comment);
667 quickie_message(CC->curr_user, NULL, CC->quickroom.QRname,
671 cprintf("%d File '%s' aborted.\n", OK, CC->upl_path);
678 * read from the download file
680 void cmd_read(char *cmdbuf)
686 start_pos = extract_long(cmdbuf, 0);
687 bytes = extract_int(cmdbuf, 1);
689 if (CC->download_fp == NULL) {
690 cprintf("%d You don't have a download file open.\n",
696 cprintf("%d You may not read more than 4096 bytes.\n",
701 fseek(CC->download_fp, start_pos, 0);
702 bytes = fread(buf, bytes, 1, CC->download_fp);
703 cprintf("%d %d\n", BINARY_FOLLOWS, bytes);
704 client_write(buf, bytes);
710 * write to the upload file
712 void cmd_writ(char *cmdbuf)
717 bytes = extract_int(cmdbuf, 0);
719 if (CC->upload_fp == NULL) {
720 cprintf("%d You don't have an upload file open.\n", ERROR);
725 cprintf("%d You may not write more than 4096 bytes.\n",
730 cprintf("%d %d\n", SEND_BINARY, bytes);
731 client_read(buf, bytes);
732 fwrite(buf, bytes, 1, CC->upload_fp);
739 * cmd_ndop() - open a network spool file for downloading
741 void cmd_ndop(char *cmdbuf)
746 if (strlen(CC->net_node) == 0) {
747 cprintf("%d Not authenticated as a network node.\n",
748 ERROR + NOT_LOGGED_IN);
752 if (CC->download_fp != NULL) {
753 cprintf("%d You already have a download file open.\n",
758 snprintf(pathname, sizeof pathname, "%s/network/spoolout/%s",
759 BBSDIR, CC->net_node);
761 /* first open the file in append mode in order to create a
762 * zero-length file if it doesn't already exist
764 CC->download_fp = fopen(pathname, "a");
765 if (CC->download_fp != NULL)
766 fclose(CC->download_fp);
769 CC->download_fp = fopen(pathname, "r");
770 if (CC->download_fp == NULL) {
771 cprintf("%d cannot open %s: %s\n",
772 ERROR, pathname, strerror(errno));
777 /* set this flag so other routines know that the download file
778 * currently open is a network spool file
782 stat(pathname, &statbuf);
783 cprintf("%d %ld\n", OK, (long)statbuf.st_size);
787 * cmd_nuop() - open a network spool file for uploading
789 void cmd_nuop(char *cmdbuf)
793 if (strlen(CC->net_node) == 0) {
794 cprintf("%d Not authenticated as a network node.\n",
795 ERROR + NOT_LOGGED_IN);
799 if (CC->upload_fp != NULL) {
800 cprintf("%d You already have an upload file open.\n",
805 snprintf(CC->upl_path, sizeof CC->upl_path,
806 "%s/network/spoolin/%s.%04x.%04x",
807 BBSDIR, CC->net_node, getpid(), ++seq);
809 CC->upload_fp = fopen(CC->upl_path, "r");
810 if (CC->upload_fp != NULL) {
811 fclose(CC->upload_fp);
812 CC->upload_fp = NULL;
813 cprintf("%d '%s' already exists\n",
814 ERROR + ALREADY_EXISTS, CC->upl_path);
818 CC->upload_fp = fopen(CC->upl_path, "w");
819 if (CC->upload_fp == NULL) {
820 cprintf("%d Cannot open %s: %s\n",
821 ERROR, CC->upl_path, strerror(errno));
825 CC->upload_type = UPL_NET;
826 cprintf("%d Ok\n", OK);