From 447b799b728618a3ff308cd363944095a33384a9 Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Mon, 1 Feb 1999 02:22:41 +0000 Subject: [PATCH] Added the OPNA command for downloading attachments --- citadel/ChangeLog | 1 + citadel/citserver.c | 4 ++ citadel/file_ops.c | 9 ++-- citadel/file_ops.h | 2 +- citadel/msgbase.c | 86 +++++++++++++++++++++++++++++++++++++ citadel/msgbase.h | 3 +- citadel/server.h | 4 +- citadel/techdoc/session.txt | 20 ++++++++- 8 files changed, 120 insertions(+), 9 deletions(-) diff --git a/citadel/ChangeLog b/citadel/ChangeLog index 1a50c2fd4..dfb75e731 100644 --- a/citadel/ChangeLog +++ b/citadel/ChangeLog @@ -2,6 +2,7 @@ Sun Jan 31 18:29:18 EST 1999 Art Cancro * Added qpdecode.c to the distribution (decodes quoted-printable) * Finished the MIME parser * Gave MSG0 a reasonable behaviour for MIME messages + * Added the OPNA command for downloading attachments Sat Jan 30 18:39:53 EST 1999 Art Cancro * Look for citadel.rc in current directory if not found elsewhere diff --git a/citadel/citserver.c b/citadel/citserver.c index 95a321411..70fa577fd 100644 --- a/citadel/citserver.c +++ b/citadel/citserver.c @@ -838,6 +838,10 @@ void *context_loop(struct CitContext *con) cmd_msg4(&cmdbuf[5]); } + else if (!strncasecmp(cmdbuf,"OPNA",4)) { + cmd_opna(&cmdbuf[5]); + } + else if (!strncasecmp(cmdbuf,"INFO",4)) { cmd_info(); } diff --git a/citadel/file_ops.c b/citadel/file_ops.c index 40d8289e3..e80876669 100644 --- a/citadel/file_ops.c +++ b/citadel/file_ops.c @@ -229,11 +229,12 @@ void cmd_netf(char *cmdbuf) * It examines the file and displays the OK result code and some information * about the file. NOTE: this stuff is Unix dependent. */ -void OpenCmdResult(void) { +void OpenCmdResult(char *filename, char *mime_type) { struct stat statbuf; fstat(fileno(CC->download_fp), &statbuf); - cprintf("%d %ld|%ld\n", OK, statbuf.st_size, statbuf.st_mtime); + cprintf("%d %ld|%ld|%s|%s\n", OK, statbuf.st_size, statbuf.st_mtime, + filename, mime_type); } @@ -282,7 +283,7 @@ void cmd_open(char *cmdbuf) return; } - OpenCmdResult(); + OpenCmdResult(filename, "application/octet-stream"); } /* @@ -342,7 +343,7 @@ void cmd_oimg(char *cmdbuf) return; } - OpenCmdResult(); + OpenCmdResult(pathname, "image/gif"); } /* diff --git a/citadel/file_ops.h b/citadel/file_ops.h index 54f25d2dc..014ae556b 100644 --- a/citadel/file_ops.h +++ b/citadel/file_ops.h @@ -2,7 +2,7 @@ void cmd_delf (char *filename); void cmd_movf (char *cmdbuf); void cmd_netf (char *cmdbuf); -void OpenCmdResult (void); +void OpenCmdResult (char *, char *); void cmd_open (char *cmdbuf); void cmd_oimg (char *cmdbuf); void cmd_uopn (char *cmdbuf); diff --git a/citadel/msgbase.c b/citadel/msgbase.c index 5fb3c4b6c..9a037ea3c 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -18,6 +18,7 @@ #include "sysdep_decls.h" #include "room_ops.h" #include "user_ops.h" +#include "file_ops.h" #include "control.h" #include "dynloader.h" #include "tools.h" @@ -362,6 +363,41 @@ void fixed_output(char *name, char *filename, char *partnum, char *disp, } +/* + * Callback function for mime parser that opens a section for downloading + */ +void mime_download(char *name, char *filename, char *partnum, char *disp, + void *content, char *cbtype, size_t length) { + + char tmpname[PATH_MAX]; + static int seq = 0; + + /* Silently go away if there's already a download open... */ + if (CC->download_fp != NULL) return; + + /* ...or if this is not the desired section */ + if (strcasecmp(CC->desired_section, partnum)) return; + + snprintf(tmpname, sizeof tmpname, + "/tmp/CitServer.download.%4x.%4x", getpid(), ++seq); + + CC->download_fp = fopen(tmpname, "wb+"); + if (CC->download_fp == NULL) return; + + /* Unlink the file while it's open, to guarantee that the + * temp file will always be deleted. + */ + unlink(tmpname); + + fwrite(content, length, 1, CC->download_fp); + fflush(CC->download_fp); + rewind(CC->download_fp); + + OpenCmdResult(filename, cbtype); + } + + + /* * Get a message off disk. (return value is the message's timestamp) * @@ -450,6 +486,41 @@ time_t output_message(char *msgid, int mode, int headers_only) { anon_flag = *mptr++; format_type = *mptr++; + /* Are we downloading a MIME component? */ + if (mode == MT_DOWNLOAD) { + if (format_type != 4) { + cprintf("%d This is not a MIME message.\n", + ERROR); + } + else if (CC->download_fp != NULL) { + cprintf("%d You already have a download open.\n", + ERROR); + } + else { + /* Skip to the message body */ + while(ch = *mptr++, (ch!='M' && ch!=0)) { + buf[0] = 0; + do { + buf[strlen(buf)+1] = 0; + rch = *mptr++; + buf[strlen(buf)] = rch; + } while (rch > 0); + } + /* Now parse it */ + mime_parser(mptr, NULL, *mime_download); + /* If there's no file open by this time, the requested + * section wasn't found, so print an error + */ + if (CC->download_fp == NULL) { + cprintf("%d Section %s not found.\n", + ERROR+FILE_NOT_FOUND, + CC->desired_section); + } + } + cdb_free(dmsgtext); + return(xtime); + } + /* Are we just looking for the message date? */ if (mode == MT_DATE) while(ch = *mptr++, (ch!='M' && ch!=0)) { buf[0] = 0; @@ -697,6 +768,21 @@ void cmd_msg4(char *cmdbuf) +/* + * Open a component of a MIME message as a download file + */ +void cmd_opna(char *cmdbuf) +{ + char msgid[256]; + + extract(msgid, cmdbuf, 0); + extract(CC->desired_section, cmdbuf, 1); + + output_message(msgid, MT_DOWNLOAD, 0); + } + + + /* * Message base operation to send a message to the master file * (returns new message number) diff --git a/citadel/msgbase.h b/citadel/msgbase.h index aa969dba2..4331d598b 100644 --- a/citadel/msgbase.h +++ b/citadel/msgbase.h @@ -6,11 +6,12 @@ void help_subst (char *strbuf, char *source, char *dest); void do_help_subst (char *buffer); void memfmout (int width, char *mptr, char subst); void output_mime_parts(char *); -time_t output_message (char *msgid, int mode, int headers_only); +time_t output_message (char *, int, int); void cmd_msg0 (char *cmdbuf); void cmd_msg2 (char *cmdbuf); void cmd_msg3 (char *cmdbuf); void cmd_msg4 (char *cmdbuf); +void cmd_opna (char *cmdbuf); long int send_message (char *message_in_memory, size_t message_length, int generate_id); void loadtroom (void); diff --git a/citadel/server.h b/citadel/server.h index 4f5a87fc0..a7a93c1b2 100644 --- a/citadel/server.h +++ b/citadel/server.h @@ -36,7 +36,7 @@ struct CitContext { int client_socket; char *ExpressMessages; int cs_pid; /* session ID */ - char cs_room[20]; /* current room */ + char cs_room[ROOMNAMELEN]; /* current room */ time_t cs_lastupdt; /* time of last update */ time_t lastcmd; /* time of last command executed */ time_t lastidle; /* For computing idle time */ @@ -67,6 +67,7 @@ struct CitContext { char last_pager[32]; /* The username of the last pager */ int FloorBeingSearched; /* This is used by cmd_lrms() etc. */ + char desired_section[64]; /* This is used for MIME downloads */ }; typedef struct CitContext t_context; @@ -124,6 +125,7 @@ struct ChatLine { #define MT_RFC822 2 /* RFC822 */ #define MT_RAW 3 /* IGnet raw format */ #define MT_MIME 4 /* MIME-formatted message */ +#define MT_DOWNLOAD 5 /* Download a component */ /* diff --git a/citadel/techdoc/session.txt b/citadel/techdoc/session.txt index a857929b8..f535a74c8 100644 --- a/citadel/techdoc/session.txt +++ b/citadel/techdoc/session.txt @@ -1001,8 +1001,8 @@ file resides. Possible return codes are: OK (file is open) If the file is successfully opened, OK will be returned, along with the -size (in bytes) of the file, and (in version 5.00 and above) the time of last -modification. +size (in bytes) of the file, the time of last modification (if applicable), +the filename (if known), and the MIME type of the file (if known). CLOS (CLOSe the download file) @@ -1635,3 +1635,19 @@ succeeds; otherwise it returns an ERROR code. This command is probably temporary, until we can work some sort of scheduler into the system. It is implemented in the serv_expire module. + + + + MSG4 (read MeSsaGe, mode 4 -- enumerate MIME parts) + + FIX ... do the writeup for this once it's done. + + + + OPNA (OPeN Attachment) + + Opens, as a download file, a component of a MIME-encoded message. The two +parameters which must be passed to this command are the message number and the +name of the desired section. If the message or section does not exist, an +appropriate ERROR code will be returned; otherwise, if the open is successful, +this command will succeed returning the same information as an OPEN command. -- 2.30.2