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>
31 #include <libcitadel.h>
36 #include "sysdep_decls.h"
41 #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 (IsEmptyStr(nttlist
)) 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 ( (!IsEmptyStr(buf
))
81 && (strcasecmp(buf
, nodename
)) ) {
91 if (nttlist
== NULL
) break;
92 if (IsEmptyStr(nttlist
)) 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
) CtdlLogPrintf(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 (IsEmptyStr(filename
)) {
126 cprintf("%d You must specify a file name.\n",
127 ERROR
+ FILE_NOT_FOUND
);
130 for (a
= 0; !IsEmptyStr(&filename
[a
]); ++a
) {
131 if ( (filename
[a
] == '/') || (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 (IsEmptyStr(filename
)) {
177 cprintf("%d You must specify a file name.\n",
178 ERROR
+ FILE_NOT_FOUND
);
182 for (a
= 0; !IsEmptyStr(&filename
[a
]); ++a
) {
183 if ( (filename
[a
] == '/') || (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 * This code is common to all commands which open a file for downloading,
224 * regardless of whether it's a file from the directory, an image, a network
225 * spool file, a MIME attachment, etc.
226 * It examines the file and displays the OK result code and some information
227 * about the file. NOTE: this stuff is Unix dependent.
229 void OpenCmdResult(char *filename
, const char *mime_type
)
235 fstat(fileno(CC
->download_fp
), &statbuf
);
236 filesize
= (long) statbuf
.st_size
;
237 modtime
= (time_t) statbuf
.st_mtime
;
239 cprintf("%d %ld|%ld|%s|%s\n",
240 CIT_OK
, filesize
, (long)modtime
, filename
, mime_type
);
245 * open a file for downloading
247 void cmd_open(char *cmdbuf
)
250 char pathname
[PATH_MAX
];
253 extract_token(filename
, cmdbuf
, 0, '|', sizeof filename
);
255 if (CtdlAccessCheck(ac_logged_in
)) return;
257 if ((CC
->room
.QRflags
& QR_DIRECTORY
) == 0) {
258 cprintf("%d No directory in this room.\n",
263 if (IsEmptyStr(filename
)) {
264 cprintf("%d You must specify a file name.\n",
265 ERROR
+ FILE_NOT_FOUND
);
269 if (CC
->download_fp
!= NULL
) {
270 cprintf("%d You already have a download file open.\n",
271 ERROR
+ RESOURCE_BUSY
);
275 for (a
= 0; !IsEmptyStr(&filename
[a
]); ++a
) {
276 if ( (filename
[a
] == '/') || (filename
[a
] == '\\') ) {
281 snprintf(pathname
, sizeof pathname
,
284 CC
->room
.QRdirname
, filename
);
285 CC
->download_fp
= fopen(pathname
, "r");
287 if (CC
->download_fp
== NULL
) {
288 cprintf("%d cannot open %s: %s\n",
289 ERROR
+ INTERNAL_ERROR
, pathname
, strerror(errno
));
293 OpenCmdResult(filename
, "application/octet-stream");
299 void cmd_oimg(char *cmdbuf
)
302 char pathname
[PATH_MAX
];
303 char MimeTestBuf
[32];
304 struct ctdluser usbuf
;
305 char which_user
[USERNAME_SIZE
];
309 extract_token(filename
, cmdbuf
, 0, '|', sizeof filename
);
311 if (IsEmptyStr(filename
)) {
312 cprintf("%d You must specify a file name.\n",
313 ERROR
+ FILE_NOT_FOUND
);
317 if (CC
->download_fp
!= NULL
) {
318 cprintf("%d You already have a download file open.\n",
319 ERROR
+ RESOURCE_BUSY
);
323 if (!strcasecmp(filename
, "_userpic_")) {
324 extract_token(which_user
, cmdbuf
, 1, '|', sizeof which_user
);
325 if (getuser(&usbuf
, which_user
) != 0) {
326 cprintf("%d No such user.\n",
327 ERROR
+ NO_SUCH_USER
);
330 snprintf(pathname
, sizeof pathname
,
334 } else if (!strcasecmp(filename
, "_floorpic_")) {
335 which_floor
= extract_int(cmdbuf
, 1);
336 snprintf(pathname
, sizeof pathname
,
338 ctdl_image_dir
, which_floor
);
339 } else if (!strcasecmp(filename
, "_roompic_")) {
340 assoc_file_name(pathname
, sizeof pathname
, &CC
->room
, ctdl_image_dir
);
342 for (a
= 0; !IsEmptyStr(&filename
[a
]); ++a
) {
343 filename
[a
] = tolower(filename
[a
]);
344 if ( (filename
[a
] == '/') || (filename
[a
] == '\\') ) {
348 snprintf(pathname
, sizeof pathname
,
354 CC
->download_fp
= fopen(pathname
, "rb");
355 if (CC
->download_fp
== NULL
) {
356 strcat(pathname
, ".gif");
357 CC
->download_fp
= fopen(pathname
, "rb");
359 if (CC
->download_fp
== NULL
) {
360 cprintf("%d Cannot open %s: %s\n",
361 ERROR
+ FILE_NOT_FOUND
, pathname
, strerror(errno
));
364 fread(&MimeTestBuf
[0], 1, 32, CC
->download_fp
);
365 rewind (CC
->download_fp
);
366 OpenCmdResult(pathname
, GuessMimeType(&MimeTestBuf
[0], 32));
370 * open a file for uploading
372 void cmd_uopn(char *cmdbuf
)
376 extract_token(CC
->upl_file
, cmdbuf
, 0, '|', sizeof CC
->upl_file
);
377 extract_token(CC
->upl_mimetype
, cmdbuf
, 1, '|', sizeof CC
->upl_mimetype
);
378 extract_token(CC
->upl_comment
, cmdbuf
, 2, '|', sizeof CC
->upl_comment
);
380 if (CtdlAccessCheck(ac_logged_in
)) return;
382 if ((CC
->room
.QRflags
& QR_DIRECTORY
) == 0) {
383 cprintf("%d No directory in this room.\n",
388 if (IsEmptyStr(CC
->upl_file
)) {
389 cprintf("%d You must specify a file name.\n",
390 ERROR
+ FILE_NOT_FOUND
);
394 if (CC
->upload_fp
!= NULL
) {
395 cprintf("%d You already have a upload file open.\n",
396 ERROR
+ RESOURCE_BUSY
);
400 for (a
= 0; !IsEmptyStr(&CC
->upl_file
[a
]); ++a
) {
401 if ( (CC
->upl_file
[a
] == '/') || (CC
->upl_file
[a
] == '\\') ) {
402 CC
->upl_file
[a
] = '_';
405 snprintf(CC
->upl_path
, sizeof CC
->upl_path
,
408 CC
->room
.QRdirname
, CC
->upl_file
);
409 snprintf(CC
->upl_filedir
, sizeof CC
->upl_filedir
,
414 CC
->upload_fp
= fopen(CC
->upl_path
, "r");
415 if (CC
->upload_fp
!= NULL
) {
416 fclose(CC
->upload_fp
);
417 CC
->upload_fp
= NULL
;
418 cprintf("%d '%s' already exists\n",
419 ERROR
+ ALREADY_EXISTS
, CC
->upl_path
);
423 CC
->upload_fp
= fopen(CC
->upl_path
, "wb");
424 if (CC
->upload_fp
== NULL
) {
425 cprintf("%d Cannot open %s: %s\n",
426 ERROR
+ INTERNAL_ERROR
, CC
->upl_path
, strerror(errno
));
429 cprintf("%d Ok\n", CIT_OK
);
435 * open an image file for uploading
437 void cmd_uimg(char *cmdbuf
)
439 int is_this_for_real
;
444 if (num_parms(cmdbuf
) < 2) {
445 cprintf("%d Usage error.\n", ERROR
+ ILLEGAL_VALUE
);
449 is_this_for_real
= extract_int(cmdbuf
, 0);
450 extract_token(CC
->upl_mimetype
, cmdbuf
, 1, '|', sizeof CC
->upl_mimetype
);
451 extract_token(basenm
, cmdbuf
, 2, '|', sizeof basenm
);
452 if (CC
->upload_fp
!= NULL
) {
453 cprintf("%d You already have an upload file open.\n",
454 ERROR
+ RESOURCE_BUSY
);
458 strcpy(CC
->upl_path
, "");
460 for (a
= 0; !IsEmptyStr(&basenm
[a
]); ++a
) {
461 basenm
[a
] = tolower(basenm
[a
]);
462 if ( (basenm
[a
] == '/') || (basenm
[a
] == '\\') ) {
467 if (CC
->user
.axlevel
>= 6) {
468 snprintf(CC
->upl_path
, sizeof CC
->upl_path
,
474 if (!strcasecmp(basenm
, "_userpic_")) {
475 snprintf(CC
->upl_path
, sizeof CC
->upl_path
,
481 if ((!strcasecmp(basenm
, "_floorpic_"))
482 && (CC
->user
.axlevel
>= 6)) {
483 which_floor
= extract_int(cmdbuf
, 2);
484 snprintf(CC
->upl_path
, sizeof CC
->upl_path
,
490 if ((!strcasecmp(basenm
, "_roompic_")) && (is_room_aide())) {
491 assoc_file_name(CC
->upl_path
, sizeof CC
->upl_path
, &CC
->room
, ctdl_image_dir
);
494 if (IsEmptyStr(CC
->upl_path
)) {
495 cprintf("%d Higher access required.\n",
496 ERROR
+ HIGHER_ACCESS_REQUIRED
);
500 if (is_this_for_real
== 0) {
501 cprintf("%d Ok to send image\n", CIT_OK
);
505 CC
->upload_fp
= fopen(CC
->upl_path
, "wb");
506 if (CC
->upload_fp
== NULL
) {
507 cprintf("%d Cannot open %s: %s\n",
508 ERROR
+ INTERNAL_ERROR
, CC
->upl_path
, strerror(errno
));
511 cprintf("%d Ok\n", CIT_OK
);
512 CC
->upload_type
= UPL_IMAGE
;
517 * close the download file
523 if (CC
->download_fp
== NULL
) {
524 cprintf("%d You don't have a download file open.\n",
525 ERROR
+ RESOURCE_NOT_OPEN
);
529 fclose(CC
->download_fp
);
530 CC
->download_fp
= NULL
;
532 if (CC
->dl_is_net
== 1) {
534 snprintf(buf
, sizeof buf
,
541 cprintf("%d Ok\n", CIT_OK
);
548 void abort_upl(struct CitContext
*who
)
550 if (who
->upload_fp
!= NULL
) {
551 fclose(who
->upload_fp
);
552 who
->upload_fp
= NULL
;
553 unlink(CC
->upl_path
);
560 * close the upload file
562 void cmd_ucls(char *cmd
)
565 char upload_notice
[512];
567 if (CC
->upload_fp
== NULL
) {
568 cprintf("%d You don't have an upload file open.\n", ERROR
+ RESOURCE_NOT_OPEN
);
572 fclose(CC
->upload_fp
);
573 CC
->upload_fp
= NULL
;
575 if ((!strcasecmp(cmd
, "1")) && (CC
->upload_type
!= UPL_FILE
)) {
576 CC
->upload_type
= UPL_FILE
;
577 cprintf("%d Upload completed.\n", CIT_OK
);
579 /* FIXME ... here we need to trigger a network run */
584 if (!strcasecmp(cmd
, "1")) {
585 cprintf("%d File '%s' saved.\n", CIT_OK
, CC
->upl_path
);
586 fp
= fopen(CC
->upl_filedir
, "a");
588 fp
= fopen(CC
->upl_filedir
, "w");
591 fprintf(fp
, "%s %s %s\n", CC
->upl_file
,
597 /* put together an upload notice */
598 snprintf(upload_notice
, sizeof upload_notice
,
599 "NEW UPLOAD: '%s'\n %s\n%s\n",
603 quickie_message(CC
->curr_user
, NULL
, NULL
, CC
->room
.QRname
,
604 upload_notice
, 0, NULL
);
607 cprintf("%d File '%s' aborted.\n", CIT_OK
, CC
->upl_path
);
614 * read from the download file
616 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",
628 ERROR
+ RESOURCE_NOT_OPEN
);
632 if (bytes
> 100000) bytes
= 100000;
633 buf
= malloc(bytes
+ 1);
635 fseek(CC
->download_fp
, start_pos
, 0);
636 actual_bytes
= fread(buf
, 1, bytes
, CC
->download_fp
);
637 cprintf("%d %d\n", BINARY_FOLLOWS
, (int)actual_bytes
);
638 client_write(buf
, actual_bytes
);
645 * write to the upload file
647 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
+ RESOURCE_NOT_OPEN
);
661 if (bytes
> 100000) {
662 cprintf("%d You may not write more than 100000 bytes.\n",
667 cprintf("%d %d\n", SEND_BINARY
, bytes
);
668 buf
= malloc(bytes
+ 1);
669 client_read(buf
, bytes
);
670 fwrite(buf
, bytes
, 1, CC
->upload_fp
);
678 * cmd_ndop() - open a network spool file for downloading
680 void cmd_ndop(char *cmdbuf
)
685 if (IsEmptyStr(CC
->net_node
)) {
686 cprintf("%d Not authenticated as a network node.\n",
687 ERROR
+ NOT_LOGGED_IN
);
691 if (CC
->download_fp
!= NULL
) {
692 cprintf("%d You already have a download file open.\n",
693 ERROR
+ RESOURCE_BUSY
);
697 snprintf(pathname
, sizeof pathname
,
702 /* first open the file in append mode in order to create a
703 * zero-length file if it doesn't already exist
705 CC
->download_fp
= fopen(pathname
, "a");
706 if (CC
->download_fp
!= NULL
)
707 fclose(CC
->download_fp
);
710 CC
->download_fp
= fopen(pathname
, "r");
711 if (CC
->download_fp
== NULL
) {
712 cprintf("%d cannot open %s: %s\n",
713 ERROR
+ INTERNAL_ERROR
, pathname
, strerror(errno
));
718 /* set this flag so other routines know that the download file
719 * currently open is a network spool file
723 stat(pathname
, &statbuf
);
724 cprintf("%d %ld\n", CIT_OK
, (long)statbuf
.st_size
);
728 * cmd_nuop() - open a network spool file for uploading
730 void cmd_nuop(char *cmdbuf
)
734 if (IsEmptyStr(CC
->net_node
)) {
735 cprintf("%d Not authenticated as a network node.\n",
736 ERROR
+ NOT_LOGGED_IN
);
740 if (CC
->upload_fp
!= NULL
) {
741 cprintf("%d You already have an upload file open.\n",
742 ERROR
+ RESOURCE_BUSY
);
746 snprintf(CC
->upl_path
, sizeof CC
->upl_path
,
753 CC
->upload_fp
= fopen(CC
->upl_path
, "r");
754 if (CC
->upload_fp
!= NULL
) {
755 fclose(CC
->upload_fp
);
756 CC
->upload_fp
= NULL
;
757 cprintf("%d '%s' already exists\n",
758 ERROR
+ ALREADY_EXISTS
, CC
->upl_path
);
762 CC
->upload_fp
= fopen(CC
->upl_path
, "w");
763 if (CC
->upload_fp
== NULL
) {
764 cprintf("%d Cannot open %s: %s\n",
765 ERROR
+ INTERNAL_ERROR
, CC
->upl_path
, strerror(errno
));
769 CC
->upload_type
= UPL_NET
;
770 cprintf("%d Ok\n", CIT_OK
);