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 * Server command to delete a file from a room's directory
51 void cmd_delf(char *filename)
56 if (CtdlAccessCheck(ac_room_aide))
59 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
60 cprintf("%d No directory in this room.\n",
65 if (strlen(filename) == 0) {
66 cprintf("%d You must specify a file name.\n",
67 ERROR + FILE_NOT_FOUND);
70 for (a = 0; a < strlen(filename); ++a) {
71 if (filename[a] == '/') {
75 snprintf(pathname, sizeof pathname, "./files/%s/%s",
76 CC->quickroom.QRdirname, filename);
79 cprintf("%d File '%s' deleted.\n", OK, pathname);
82 cprintf("%d File '%s' not found.\n",
83 ERROR + FILE_NOT_FOUND, pathname);
91 * move a file from one room directory to another
93 void cmd_movf(char *cmdbuf)
101 struct quickroom qrbuf;
103 extract(filename, cmdbuf, 0);
104 extract(newroom, cmdbuf, 1);
106 if (CtdlAccessCheck(ac_room_aide)) return;
108 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
109 cprintf("%d No directory in this room.\n",
114 if (strlen(filename) == 0) {
115 cprintf("%d You must specify a file name.\n",
116 ERROR + FILE_NOT_FOUND);
120 for (a = 0; a < strlen(filename); ++a) {
121 if (filename[a] == '/') {
125 snprintf(pathname, sizeof pathname, "./files/%s/%s",
126 CC->quickroom.QRdirname, filename);
127 if (access(pathname, 0) != 0) {
128 cprintf("%d File '%s' not found.\n",
129 ERROR + FILE_NOT_FOUND, pathname);
133 if (getroom(&qrbuf, newroom) != 0) {
134 cprintf("%d '%s' does not exist.\n", ERROR, newroom);
137 if ((qrbuf.QRflags & QR_DIRECTORY) == 0) {
138 cprintf("%d '%s' is not a directory room.\n",
139 ERROR + NOT_HERE, qrbuf.QRname);
142 snprintf(newpath, sizeof newpath, "./files/%s/%s", qrbuf.QRdirname,
144 if (link(pathname, newpath) != 0) {
145 cprintf("%d Couldn't move file: %s\n", ERROR,
151 /* this is a crude method of copying the file description */
152 snprintf(buf, sizeof buf,
153 "cat ./files/%s/filedir |grep %s >>./files/%s/filedir",
154 CC->quickroom.QRdirname, filename, qrbuf.QRdirname);
156 cprintf("%d File '%s' has been moved.\n", OK, filename);
161 * send a file over the net
163 void cmd_netf(char *cmdbuf)
165 char pathname[SIZ], filename[SIZ], destsys[SIZ], buf[SIZ];
172 extract(filename, cmdbuf, 0);
173 extract(destsys, cmdbuf, 1);
175 if (CtdlAccessCheck(ac_room_aide)) return;
177 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
178 cprintf("%d No directory in this room.\n",
183 if (strlen(filename) == 0) {
184 cprintf("%d You must specify a file name.\n",
185 ERROR + FILE_NOT_FOUND);
189 for (a = 0; a < strlen(filename); ++a) {
190 if (filename[a] == '/') {
194 snprintf(pathname, sizeof pathname, "./files/%s/%s",
195 CC->quickroom.QRdirname, filename);
196 if (access(pathname, 0) != 0) {
197 cprintf("%d File '%s' not found.\n",
198 ERROR + FILE_NOT_FOUND, pathname);
201 snprintf(buf, sizeof buf, "sysop@%s", destsys);
203 if (e != MES_BINARY) {
204 cprintf("%d No such system: '%s'\n",
205 ERROR + NO_SUCH_SYSTEM, destsys);
208 snprintf(outfile, sizeof outfile,
209 "%s/network/spoolin/nsf.%04x.%04x",
210 BBSDIR, getpid(), ++seq);
211 ofp = fopen(outfile, "a");
213 cprintf("%d internal error\n", ERROR);
218 putc(MES_NORMAL, ofp);
220 fprintf(ofp, "Pcit%ld", CC->usersupp.usernum);
223 fprintf(ofp, "T%ld", (long) now);
225 fprintf(ofp, "A%s", CC->usersupp.fullname);
227 fprintf(ofp, "O%s", CC->quickroom.QRname);
229 fprintf(ofp, "N%s", NODENAME);
231 fprintf(ofp, "D%s", destsys);
233 fprintf(ofp, "SFILE");
238 snprintf(buf, sizeof buf,
239 "cd ./files/%s; uuencode %s <%s 2>/dev/null >>%s",
240 CC->quickroom.QRdirname, filename, filename, outfile);
243 ofp = fopen(outfile, "a");
247 cprintf("%d File '%s' has been sent to %s.\n", OK, filename,
249 system("nohup ./netproc -i >/dev/null 2>&1 &");
254 * This code is common to all commands which open a file for downloading,
255 * regardless of whether it's a file from the directory, an image, a network
256 * spool file, a MIME attachment, etc.
257 * It examines the file and displays the OK result code and some information
258 * about the file. NOTE: this stuff is Unix dependent.
260 void OpenCmdResult(char *filename, char *mime_type)
266 fstat(fileno(CC->download_fp), &statbuf);
267 filesize = (long) statbuf.st_size;
268 modtime = (time_t) statbuf.st_mtime;
270 cprintf("%d %ld|%ld|%s|%s\n",
271 OK, filesize, modtime, filename, mime_type);
276 * open a file for downloading
278 void cmd_open(char *cmdbuf)
284 extract(filename, cmdbuf, 0);
286 if (CtdlAccessCheck(ac_logged_in)) return;
288 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
289 cprintf("%d No directory in this room.\n",
294 if (strlen(filename) == 0) {
295 cprintf("%d You must specify a file name.\n",
296 ERROR + FILE_NOT_FOUND);
300 if (CC->download_fp != NULL) {
301 cprintf("%d You already have a download file open.\n",
306 for (a = 0; a < strlen(filename); ++a) {
307 if (filename[a] == '/') {
312 snprintf(pathname, sizeof pathname,
313 "./files/%s/%s", CC->quickroom.QRdirname, filename);
314 CC->download_fp = fopen(pathname, "r");
316 if (CC->download_fp == NULL) {
317 cprintf("%d cannot open %s: %s\n",
318 ERROR, pathname, strerror(errno));
322 OpenCmdResult(filename, "application/octet-stream");
328 void cmd_oimg(char *cmdbuf)
332 struct usersupp usbuf;
337 extract(filename, cmdbuf, 0);
339 if (strlen(filename) == 0) {
340 cprintf("%d You must specify a file name.\n",
341 ERROR + FILE_NOT_FOUND);
345 if (CC->download_fp != NULL) {
346 cprintf("%d You already have a download file open.\n",
351 if (!strcasecmp(filename, "_userpic_")) {
352 extract(which_user, cmdbuf, 1);
353 if (getuser(&usbuf, which_user) != 0) {
354 cprintf("%d No such user.\n",
355 ERROR + NO_SUCH_USER);
358 snprintf(pathname, sizeof pathname, "./userpics/%ld.gif",
360 } else if (!strcasecmp(filename, "_floorpic_")) {
361 which_floor = extract_int(cmdbuf, 1);
362 snprintf(pathname, sizeof pathname,
363 "./images/floor.%d.gif", which_floor);
364 } else if (!strcasecmp(filename, "_roompic_")) {
365 assoc_file_name(pathname, &CC->quickroom, "images");
367 for (a = 0; a < strlen(filename); ++a) {
368 filename[a] = tolower(filename[a]);
369 if (filename[a] == '/') {
373 snprintf(pathname, sizeof pathname, "./images/%s.gif",
377 CC->download_fp = fopen(pathname, "rb");
378 if (CC->download_fp == NULL) {
379 cprintf("%d Cannot open %s: %s\n",
380 ERROR + FILE_NOT_FOUND, pathname, strerror(errno));
384 OpenCmdResult(pathname, "image/gif");
388 * open a file for uploading
390 void cmd_uopn(char *cmdbuf)
394 extract(CC->upl_file, cmdbuf, 0);
395 extract(CC->upl_comment, cmdbuf, 1);
397 if (CtdlAccessCheck(ac_logged_in)) return;
399 if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
400 cprintf("%d No directory in this room.\n",
405 if (strlen(CC->upl_file) == 0) {
406 cprintf("%d You must specify a file name.\n",
407 ERROR + FILE_NOT_FOUND);
411 if (CC->upload_fp != NULL) {
412 cprintf("%d You already have a upload file open.\n",
417 for (a = 0; a < strlen(CC->upl_file); ++a) {
418 if (CC->upl_file[a] == '/') {
419 CC->upl_file[a] = '_';
422 snprintf(CC->upl_path, sizeof CC->upl_path, "./files/%s/%s",
423 CC->quickroom.QRdirname, CC->upl_file);
424 snprintf(CC->upl_filedir, sizeof CC->upl_filedir,
425 "./files/%s/filedir", CC->quickroom.QRdirname);
427 CC->upload_fp = fopen(CC->upl_path, "r");
428 if (CC->upload_fp != NULL) {
429 fclose(CC->upload_fp);
430 CC->upload_fp = NULL;
431 cprintf("%d '%s' already exists\n",
432 ERROR + ALREADY_EXISTS, CC->upl_path);
436 CC->upload_fp = fopen(CC->upl_path, "wb");
437 if (CC->upload_fp == NULL) {
438 cprintf("%d Cannot open %s: %s\n",
439 ERROR, CC->upl_path, strerror(errno));
442 cprintf("%d Ok\n", OK);
448 * open an image file for uploading
450 void cmd_uimg(char *cmdbuf)
452 int is_this_for_real;
457 if (num_parms(cmdbuf) < 2) {
458 cprintf("%d Usage error.\n", ERROR);
462 is_this_for_real = extract_int(cmdbuf, 0);
463 extract(basenm, cmdbuf, 1);
464 if (CC->upload_fp != NULL) {
465 cprintf("%d You already have an upload file open.\n",
470 strcpy(CC->upl_path, "");
472 for (a = 0; a < strlen(basenm); ++a) {
473 basenm[a] = tolower(basenm[a]);
474 if (basenm[a] == '/') {
479 if (CC->usersupp.axlevel >= 6) {
480 snprintf(CC->upl_path, sizeof CC->upl_path, "./images/%s",
484 if (!strcasecmp(basenm, "_userpic_")) {
485 snprintf(CC->upl_path, sizeof CC->upl_path,
486 "./userpics/%ld.gif", CC->usersupp.usernum);
489 if ((!strcasecmp(basenm, "_floorpic_"))
490 && (CC->usersupp.axlevel >= 6)) {
491 which_floor = extract_int(cmdbuf, 2);
492 snprintf(CC->upl_path, sizeof CC->upl_path,
493 "./images/floor.%d.gif", which_floor);
496 if ((!strcasecmp(basenm, "_roompic_")) && (is_room_aide())) {
497 assoc_file_name(CC->upl_path, &CC->quickroom, "images");
500 if (strlen(CC->upl_path) == 0) {
501 cprintf("%d Higher access required.\n",
502 ERROR + HIGHER_ACCESS_REQUIRED);
506 if (is_this_for_real == 0) {
507 cprintf("%d Ok to send image\n", OK);
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, CC->upl_path, strerror(errno));
517 cprintf("%d Ok\n", OK);
518 CC->upload_type = UPL_IMAGE;
523 * close the download file
529 if (CC->download_fp == NULL) {
530 cprintf("%d You don't have a download file open.\n",
535 fclose(CC->download_fp);
536 CC->download_fp = NULL;
538 if (CC->dl_is_net == 1) {
540 snprintf(buf, sizeof buf, "%s/network/spoolout/%s", BBSDIR,
545 cprintf("%d Ok\n", OK);
552 void abort_upl(struct CitContext *who)
554 if (who->upload_fp != NULL) {
555 fclose(who->upload_fp);
556 who->upload_fp = NULL;
557 unlink(CC->upl_path);
564 * close the upload file
566 void cmd_ucls(char *cmd)
569 char upload_notice[512];
571 if (CC->upload_fp == NULL) {
572 cprintf("%d You don't have an upload file open.\n", ERROR);
576 fclose(CC->upload_fp);
577 CC->upload_fp = NULL;
579 if ((!strcasecmp(cmd, "1")) && (CC->upload_type != UPL_FILE)) {
580 CC->upload_type = UPL_FILE;
581 cprintf("%d Upload completed.\n", OK);
583 /* FIXME ... here we need to trigger a network run */
588 if (!strcasecmp(cmd, "1")) {
589 cprintf("%d File '%s' saved.\n", OK, CC->upl_path);
590 fp = fopen(CC->upl_filedir, "a");
592 fp = fopen(CC->upl_filedir, "w");
595 fprintf(fp, "%s %s\n", CC->upl_file,
600 /* put together an upload notice */
601 sprintf(upload_notice,
602 "NEW UPLOAD: '%s'\n %s\n",
603 CC->upl_file, CC->upl_comment);
604 quickie_message(CC->curr_user, NULL, CC->quickroom.QRname,
608 cprintf("%d File '%s' aborted.\n", OK, CC->upl_path);
615 * read from the download file
617 void cmd_read(char *cmdbuf)
623 start_pos = extract_long(cmdbuf, 0);
624 bytes = extract_int(cmdbuf, 1);
626 if (CC->download_fp == NULL) {
627 cprintf("%d You don't have a download file open.\n",
633 cprintf("%d You may not read more than 4096 bytes.\n",
638 fseek(CC->download_fp, start_pos, 0);
639 fread(buf, bytes, 1, CC->download_fp);
640 cprintf("%d %d\n", BINARY_FOLLOWS, bytes);
641 client_write(buf, bytes);
647 * write to the upload file
649 void cmd_writ(char *cmdbuf)
654 bytes = extract_int(cmdbuf, 0);
656 if (CC->upload_fp == NULL) {
657 cprintf("%d You don't have an upload file open.\n", ERROR);
662 cprintf("%d You may not write more than 4096 bytes.\n",
667 cprintf("%d %d\n", SEND_BINARY, bytes);
668 client_read(buf, bytes);
669 fwrite(buf, bytes, 1, CC->upload_fp);
676 * cmd_ndop() - open a network spool file for downloading
678 void cmd_ndop(char *cmdbuf)
683 if (strlen(CC->net_node) == 0) {
684 cprintf("%d Not authenticated as a network node.\n",
685 ERROR + NOT_LOGGED_IN);
689 if (CC->download_fp != NULL) {
690 cprintf("%d You already have a download file open.\n",
695 snprintf(pathname, sizeof pathname, "%s/network/spoolout/%s",
696 BBSDIR, CC->net_node);
698 /* first open the file in append mode in order to create a
699 * zero-length file if it doesn't already exist
701 CC->download_fp = fopen(pathname, "a");
702 if (CC->download_fp != NULL)
703 fclose(CC->download_fp);
706 CC->download_fp = fopen(pathname, "r");
707 if (CC->download_fp == NULL) {
708 cprintf("%d cannot open %s: %s\n",
709 ERROR, pathname, strerror(errno));
714 /* set this flag so other routines know that the download file
715 * currently open is a network spool file
719 stat(pathname, &statbuf);
720 cprintf("%d %ld\n", OK, statbuf.st_size);
724 * cmd_nuop() - open a network spool file for uploading
726 void cmd_nuop(char *cmdbuf)
730 if (strlen(CC->net_node) == 0) {
731 cprintf("%d Not authenticated as a network node.\n",
732 ERROR + NOT_LOGGED_IN);
736 if (CC->upload_fp != NULL) {
737 cprintf("%d You already have an upload file open.\n",
742 snprintf(CC->upl_path, sizeof CC->upl_path,
743 "%s/network/spoolin/%s.%04x.%04x",
744 BBSDIR, CC->net_node, getpid(), ++seq);
746 CC->upload_fp = fopen(CC->upl_path, "r");
747 if (CC->upload_fp != NULL) {
748 fclose(CC->upload_fp);
749 CC->upload_fp = NULL;
750 cprintf("%d '%s' already exists\n",
751 ERROR + ALREADY_EXISTS, CC->upl_path);
755 CC->upload_fp = fopen(CC->upl_path, "w");
756 if (CC->upload_fp == NULL) {
757 cprintf("%d Cannot open %s: %s\n",
758 ERROR, CC->upl_path, strerror(errno));
762 CC->upload_type = UPL_NET;
763 cprintf("%d Ok\n", OK);