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>
33 #include "serv_extensions.h"
36 #include "sysdep_decls.h"
42 #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 = strdup("");
65 if (nttlist == NULL) break;
66 nttlist = (char *)realloc(nttlist,
67 (strlen(nttlist) + strlen(nodename) + 3) );
69 strcat(nttlist, nodename);
73 if (nttlist == NULL) break;
74 if (strlen(nttlist) == 0) break;
75 ptr = malloc(strlen(nttlist));
76 if (ptr == NULL) break;
78 for (i = 0; i < num_tokens(nttlist, '|'); ++i) {
79 extract_token(buf, nttlist, i, '|', sizeof buf);
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_token(buf, nttlist, i, '|', sizeof buf);
95 if (!strcasecmp(buf, nodename)) ++retval;
100 if (nttlist != NULL) lprintf(CTDL_DEBUG, "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->room.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,
138 CC->room.QRdirname, filename);
139 a = unlink(pathname);
141 cprintf("%d File '%s' deleted.\n", CIT_OK, pathname);
144 cprintf("%d File '%s' not found.\n",
145 ERROR + FILE_NOT_FOUND, pathname);
153 * move a file from one room directory to another
155 void cmd_movf(char *cmdbuf)
157 char filename[PATH_MAX];
158 char pathname[PATH_MAX];
159 char newpath[PATH_MAX];
160 char newroom[ROOMNAMELEN];
163 struct ctdlroom qrbuf;
165 extract_token(filename, cmdbuf, 0, '|', sizeof filename);
166 extract_token(newroom, cmdbuf, 1, '|', sizeof newroom);
168 if (CtdlAccessCheck(ac_room_aide)) return;
170 if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
171 cprintf("%d No directory in this room.\n",
176 if (strlen(filename) == 0) {
177 cprintf("%d You must specify a file name.\n",
178 ERROR + FILE_NOT_FOUND);
182 for (a = 0; a < strlen(filename); ++a) {
183 if (filename[a] == '/') {
187 snprintf(pathname, sizeof pathname, "./files/%s/%s",
188 CC->room.QRdirname, filename);
189 if (access(pathname, 0) != 0) {
190 cprintf("%d File '%s' not found.\n",
191 ERROR + FILE_NOT_FOUND, pathname);
195 if (getroom(&qrbuf, newroom) != 0) {
196 cprintf("%d '%s' does not exist.\n", ERROR + ROOM_NOT_FOUND, newroom);
199 if ((qrbuf.QRflags & QR_DIRECTORY) == 0) {
200 cprintf("%d '%s' is not a directory room.\n",
201 ERROR + NOT_HERE, qrbuf.QRname);
204 snprintf(newpath, sizeof newpath, "./files/%s/%s", qrbuf.QRdirname,
206 if (link(pathname, newpath) != 0) {
207 cprintf("%d Couldn't move file: %s\n", ERROR + INTERNAL_ERROR,
213 /* this is a crude method of copying the file description */
214 snprintf(buf, sizeof buf,
215 "cat ./files/%s/filedir |grep %s >>./files/%s/filedir",
216 CC->room.QRdirname, filename, qrbuf.QRdirname);
218 cprintf("%d File '%s' has been moved.\n", CIT_OK, filename);
223 * send a file over the net
225 void cmd_netf(char *cmdbuf)
227 char pathname[256], filename[256], destsys[256], buf[256];
234 extract_token(filename, cmdbuf, 0, '|', sizeof filename);
235 extract_token(destsys, cmdbuf, 1, '|', sizeof destsys);
237 if (CtdlAccessCheck(ac_room_aide)) return;
239 if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
240 cprintf("%d No directory in this room.\n",
245 if (strlen(filename) == 0) {
246 cprintf("%d You must specify a file name.\n",
247 ERROR + FILE_NOT_FOUND);
251 for (a = 0; a < strlen(filename); ++a) {
252 if (filename[a] == '/') {
256 snprintf(pathname, sizeof pathname, "./files/%s/%s",
257 CC->room.QRdirname, filename);
258 if (access(pathname, 0) != 0) {
259 cprintf("%d File '%s' not found.\n",
260 ERROR + FILE_NOT_FOUND, pathname);
263 snprintf(buf, sizeof buf, "sysop@%s", destsys);
265 if (e != MES_IGNET) {
266 cprintf("%d No such system: '%s'\n",
267 ERROR + NO_SUCH_SYSTEM, destsys);
270 snprintf(outfile, sizeof outfile,
273 (long)getpid(), ++seq);
274 ofp = fopen(outfile, "a");
276 cprintf("%d internal error\n", ERROR + INTERNAL_ERROR);
281 putc(MES_NORMAL, ofp);
283 fprintf(ofp, "Pcit%ld", CC->user.usernum);
286 fprintf(ofp, "T%ld", (long) now);
288 fprintf(ofp, "A%s", CC->user.fullname);
290 fprintf(ofp, "O%s", CC->room.QRname);
292 fprintf(ofp, "N%s", NODENAME);
294 fprintf(ofp, "D%s", destsys);
296 fprintf(ofp, "SFILE");
301 snprintf(buf, sizeof buf,
302 "cd %s/%s; uuencode %s <%s 2>/dev/null >>%s",
304 /* FIXME: detect uuencode while installation? or inline */
305 CC->room.QRdirname, filename, filename, outfile);
308 ofp = fopen(outfile, "a");
312 cprintf("%d File '%s' has been sent to %s.\n", CIT_OK, filename,
314 /* FIXME start a network run here. */
319 * This code is common to all commands which open a file for downloading,
320 * regardless of whether it's a file from the directory, an image, a network
321 * spool file, a MIME attachment, etc.
322 * It examines the file and displays the OK result code and some information
323 * about the file. NOTE: this stuff is Unix dependent.
325 void OpenCmdResult(char *filename, char *mime_type)
331 fstat(fileno(CC->download_fp), &statbuf);
332 filesize = (long) statbuf.st_size;
333 modtime = (time_t) statbuf.st_mtime;
335 cprintf("%d %ld|%ld|%s|%s\n",
336 CIT_OK, filesize, (long)modtime, filename, mime_type);
341 * open a file for downloading
343 void cmd_open(char *cmdbuf)
346 char pathname[PATH_MAX];
349 extract_token(filename, cmdbuf, 0, '|', sizeof filename);
351 if (CtdlAccessCheck(ac_logged_in)) return;
353 if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
354 cprintf("%d No directory in this room.\n",
359 if (strlen(filename) == 0) {
360 cprintf("%d You must specify a file name.\n",
361 ERROR + FILE_NOT_FOUND);
365 if (CC->download_fp != NULL) {
366 cprintf("%d You already have a download file open.\n",
367 ERROR + RESOURCE_BUSY);
371 for (a = 0; a < strlen(filename); ++a) {
372 if (filename[a] == '/') {
377 snprintf(pathname, sizeof pathname,
380 CC->room.QRdirname, filename);
381 CC->download_fp = fopen(pathname, "r");
383 if (CC->download_fp == NULL) {
384 cprintf("%d cannot open %s: %s\n",
385 ERROR + INTERNAL_ERROR, pathname, strerror(errno));
389 OpenCmdResult(filename, "application/octet-stream");
395 void cmd_oimg(char *cmdbuf)
398 char pathname[PATH_MAX];
399 struct ctdluser usbuf;
400 char which_user[USERNAME_SIZE];
404 extract_token(filename, cmdbuf, 0, '|', sizeof filename);
406 if (strlen(filename) == 0) {
407 cprintf("%d You must specify a file name.\n",
408 ERROR + FILE_NOT_FOUND);
412 if (CC->download_fp != NULL) {
413 cprintf("%d You already have a download file open.\n",
414 ERROR + RESOURCE_BUSY);
418 if (!strcasecmp(filename, "_userpic_")) {
419 extract_token(which_user, cmdbuf, 1, '|', sizeof which_user);
420 if (getuser(&usbuf, which_user) != 0) {
421 cprintf("%d No such user.\n",
422 ERROR + NO_SUCH_USER);
425 snprintf(pathname, sizeof pathname,
429 } else if (!strcasecmp(filename, "_floorpic_")) {
430 which_floor = extract_int(cmdbuf, 1);
431 snprintf(pathname, sizeof pathname,
433 ctdl_image_dir, which_floor);
434 } else if (!strcasecmp(filename, "_roompic_")) {
435 assoc_file_name(pathname, sizeof pathname, &CC->room, "images");
437 for (a = 0; a < strlen(filename); ++a) {
438 filename[a] = tolower(filename[a]);
439 if (filename[a] == '/') {
443 snprintf(pathname, sizeof pathname,
449 CC->download_fp = fopen(pathname, "rb");
450 if (CC->download_fp == NULL) {
451 cprintf("%d Cannot open %s: %s\n",
452 ERROR + FILE_NOT_FOUND, pathname, strerror(errno));
456 OpenCmdResult(pathname, "image/gif");
460 * open a file for uploading
462 void cmd_uopn(char *cmdbuf)
466 extract_token(CC->upl_file, cmdbuf, 0, '|', sizeof CC->upl_file);
467 extract_token(CC->upl_comment, cmdbuf, 1, '|', sizeof CC->upl_comment);
469 if (CtdlAccessCheck(ac_logged_in)) return;
471 if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
472 cprintf("%d No directory in this room.\n",
477 if (strlen(CC->upl_file) == 0) {
478 cprintf("%d You must specify a file name.\n",
479 ERROR + FILE_NOT_FOUND);
483 if (CC->upload_fp != NULL) {
484 cprintf("%d You already have a upload file open.\n",
485 ERROR + RESOURCE_BUSY);
489 for (a = 0; a < strlen(CC->upl_file); ++a) {
490 if (CC->upl_file[a] == '/') {
491 CC->upl_file[a] = '_';
494 snprintf(CC->upl_path, sizeof CC->upl_path,
497 CC->room.QRdirname, CC->upl_file);
498 snprintf(CC->upl_filedir, sizeof CC->upl_filedir,
503 CC->upload_fp = fopen(CC->upl_path, "r");
504 if (CC->upload_fp != NULL) {
505 fclose(CC->upload_fp);
506 CC->upload_fp = NULL;
507 cprintf("%d '%s' already exists\n",
508 ERROR + ALREADY_EXISTS, CC->upl_path);
512 CC->upload_fp = fopen(CC->upl_path, "wb");
513 if (CC->upload_fp == NULL) {
514 cprintf("%d Cannot open %s: %s\n",
515 ERROR + INTERNAL_ERROR, CC->upl_path, strerror(errno));
518 cprintf("%d Ok\n", CIT_OK);
524 * open an image file for uploading
526 void cmd_uimg(char *cmdbuf)
528 int is_this_for_real;
533 if (num_parms(cmdbuf) < 2) {
534 cprintf("%d Usage error.\n", ERROR + ILLEGAL_VALUE);
538 is_this_for_real = extract_int(cmdbuf, 0);
539 extract_token(basenm, cmdbuf, 1, '|', sizeof basenm);
540 if (CC->upload_fp != NULL) {
541 cprintf("%d You already have an upload file open.\n",
542 ERROR + RESOURCE_BUSY);
546 strcpy(CC->upl_path, "");
548 for (a = 0; a < strlen(basenm); ++a) {
549 basenm[a] = tolower(basenm[a]);
550 if (basenm[a] == '/') {
555 if (CC->user.axlevel >= 6) {
556 snprintf(CC->upl_path, sizeof CC->upl_path,
562 if (!strcasecmp(basenm, "_userpic_")) {
563 snprintf(CC->upl_path, sizeof CC->upl_path,
569 if ((!strcasecmp(basenm, "_floorpic_"))
570 && (CC->user.axlevel >= 6)) {
571 which_floor = extract_int(cmdbuf, 2);
572 snprintf(CC->upl_path, sizeof CC->upl_path,
578 if ((!strcasecmp(basenm, "_roompic_")) && (is_room_aide())) {
579 assoc_file_name(CC->upl_path, sizeof CC->upl_path, &CC->room, "images");
582 if (strlen(CC->upl_path) == 0) {
583 cprintf("%d Higher access required.\n",
584 ERROR + HIGHER_ACCESS_REQUIRED);
588 if (is_this_for_real == 0) {
589 cprintf("%d Ok to send image\n", CIT_OK);
593 CC->upload_fp = fopen(CC->upl_path, "wb");
594 if (CC->upload_fp == NULL) {
595 cprintf("%d Cannot open %s: %s\n",
596 ERROR + INTERNAL_ERROR, CC->upl_path, strerror(errno));
599 cprintf("%d Ok\n", CIT_OK);
600 CC->upload_type = UPL_IMAGE;
605 * close the download file
611 if (CC->download_fp == NULL) {
612 cprintf("%d You don't have a download file open.\n",
613 ERROR + RESOURCE_NOT_OPEN);
617 fclose(CC->download_fp);
618 CC->download_fp = NULL;
620 if (CC->dl_is_net == 1) {
622 snprintf(buf, sizeof buf,
629 cprintf("%d Ok\n", CIT_OK);
636 void abort_upl(struct CitContext *who)
638 if (who->upload_fp != NULL) {
639 fclose(who->upload_fp);
640 who->upload_fp = NULL;
641 unlink(CC->upl_path);
648 * close the upload file
650 void cmd_ucls(char *cmd)
653 char upload_notice[512];
655 if (CC->upload_fp == NULL) {
656 cprintf("%d You don't have an upload file open.\n", ERROR + RESOURCE_NOT_OPEN);
660 fclose(CC->upload_fp);
661 CC->upload_fp = NULL;
663 if ((!strcasecmp(cmd, "1")) && (CC->upload_type != UPL_FILE)) {
664 CC->upload_type = UPL_FILE;
665 cprintf("%d Upload completed.\n", CIT_OK);
667 /* FIXME ... here we need to trigger a network run */
672 if (!strcasecmp(cmd, "1")) {
673 cprintf("%d File '%s' saved.\n", CIT_OK, CC->upl_path);
674 fp = fopen(CC->upl_filedir, "a");
676 fp = fopen(CC->upl_filedir, "w");
679 fprintf(fp, "%s %s\n", CC->upl_file,
684 /* put together an upload notice */
685 snprintf(upload_notice, sizeof upload_notice,
686 "NEW UPLOAD: '%s'\n %s\n",
687 CC->upl_file, CC->upl_comment);
688 quickie_message(CC->curr_user, NULL, CC->room.QRname,
689 upload_notice, 0, NULL);
692 cprintf("%d File '%s' aborted.\n", CIT_OK, CC->upl_path);
699 * read from the download file
701 void cmd_read(char *cmdbuf)
708 start_pos = extract_long(cmdbuf, 0);
709 bytes = extract_int(cmdbuf, 1);
711 if (CC->download_fp == NULL) {
712 cprintf("%d You don't have a download file open.\n",
713 ERROR + RESOURCE_NOT_OPEN);
717 if (bytes > 100000) bytes = 100000;
718 buf = malloc(bytes + 1);
720 fseek(CC->download_fp, start_pos, 0);
721 actual_bytes = fread(buf, 1, bytes, CC->download_fp);
722 cprintf("%d %d\n", BINARY_FOLLOWS, (int)actual_bytes);
723 client_write(buf, actual_bytes);
730 * write to the upload file
732 void cmd_writ(char *cmdbuf)
739 bytes = extract_int(cmdbuf, 0);
741 if (CC->upload_fp == NULL) {
742 cprintf("%d You don't have an upload file open.\n", ERROR + RESOURCE_NOT_OPEN);
746 if (bytes > 100000) {
747 cprintf("%d You may not write more than 100000 bytes.\n",
752 cprintf("%d %d\n", SEND_BINARY, bytes);
753 buf = malloc(bytes + 1);
754 client_read(buf, bytes);
755 fwrite(buf, bytes, 1, CC->upload_fp);
763 * cmd_ndop() - open a network spool file for downloading
765 void cmd_ndop(char *cmdbuf)
770 if (strlen(CC->net_node) == 0) {
771 cprintf("%d Not authenticated as a network node.\n",
772 ERROR + NOT_LOGGED_IN);
776 if (CC->download_fp != NULL) {
777 cprintf("%d You already have a download file open.\n",
778 ERROR + RESOURCE_BUSY);
782 snprintf(pathname, sizeof pathname,
787 /* first open the file in append mode in order to create a
788 * zero-length file if it doesn't already exist
790 CC->download_fp = fopen(pathname, "a");
791 if (CC->download_fp != NULL)
792 fclose(CC->download_fp);
795 CC->download_fp = fopen(pathname, "r");
796 if (CC->download_fp == NULL) {
797 cprintf("%d cannot open %s: %s\n",
798 ERROR + INTERNAL_ERROR, pathname, strerror(errno));
803 /* set this flag so other routines know that the download file
804 * currently open is a network spool file
808 stat(pathname, &statbuf);
809 cprintf("%d %ld\n", CIT_OK, (long)statbuf.st_size);
813 * cmd_nuop() - open a network spool file for uploading
815 void cmd_nuop(char *cmdbuf)
819 if (strlen(CC->net_node) == 0) {
820 cprintf("%d Not authenticated as a network node.\n",
821 ERROR + NOT_LOGGED_IN);
825 if (CC->upload_fp != NULL) {
826 cprintf("%d You already have an upload file open.\n",
827 ERROR + RESOURCE_BUSY);
831 snprintf(CC->upl_path, sizeof CC->upl_path,
838 CC->upload_fp = fopen(CC->upl_path, "r");
839 if (CC->upload_fp != NULL) {
840 fclose(CC->upload_fp);
841 CC->upload_fp = NULL;
842 cprintf("%d '%s' already exists\n",
843 ERROR + ALREADY_EXISTS, CC->upl_path);
847 CC->upload_fp = fopen(CC->upl_path, "w");
848 if (CC->upload_fp == NULL) {
849 cprintf("%d Cannot open %s: %s\n",
850 ERROR + INTERNAL_ERROR, CC->upl_path, strerror(errno));
854 CC->upload_type = UPL_NET;
855 cprintf("%d Ok\n", CIT_OK);