From 2cab4fe797bfb280124292ed9889d87b37c62770 Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Wed, 13 Jan 1999 03:33:20 +0000 Subject: [PATCH] * Various changes to begin work on support for MIME messages - Defined format type 4 for MIME - msgbase.c: *temporary* hacks in output_message() for Type 4 - citmail.c: added more robust header parsing, and support for Type 4. Also eliminated the crappy built-in SMTP server. - Updated some of the technical documentation --- citadel/ChangeLog | 9 ++ citadel/citadel.h | 22 ++++ citadel/citmail.c | 222 ++++++++++++------------------------ citadel/msgbase.c | 11 +- citadel/netproc.c | 17 --- citadel/techdoc/hack.txt | 54 ++++----- citadel/techdoc/session.txt | 16 +-- 7 files changed, 147 insertions(+), 204 deletions(-) diff --git a/citadel/ChangeLog b/citadel/ChangeLog index 6e9140278..271247427 100644 --- a/citadel/ChangeLog +++ b/citadel/ChangeLog @@ -1,3 +1,12 @@ +Tue Jan 12 22:30:00 EST 1999 Art Cancro + * Various changes to begin work on support for MIME messages + - Defined format type 4 for MIME + - msgbase.c: *temporary* hacks in output_message() for Type 4 + - citmail.c: added more robust header parsing, and support + for Type 4. Also eliminated the crappy built-in + SMTP server. + - Updated some of the technical documentation + Sun Jan 10 13:34:36 EST 1999 Art Cancro * Fixed access to page log room diff --git a/citadel/citadel.h b/citadel/citadel.h index 574dd7975..7dd4b0955 100644 --- a/citadel/citadel.h +++ b/citadel/citadel.h @@ -251,4 +251,26 @@ struct floor { #define AIDEROOM "Aide" +/* + * This structure is used to hold all of the fields of a message + * during conversion, processing, or whatever. + */ +struct minfo { + char A[512]; + char B[512]; + char C[512]; + char D[512]; + char E[512]; + char G[512]; + char H[512]; + long I; + char N[512]; + char O[512]; + char P[512]; + char R[512]; + char S[512]; + long T; + char U[512]; + char nexthop[512]; + }; diff --git a/citadel/citmail.c b/citadel/citmail.c index 4a7b26c14..f533f8453 100644 --- a/citadel/citmail.c +++ b/citadel/citmail.c @@ -1,5 +1,5 @@ /* - * citmail.c v4.1 + * citmail.c v4.2 * $Id$ * * This program may be used as a local mail delivery agent, which will allow @@ -12,7 +12,6 @@ * * citmail - Deliver a message * citmail -t - Address test mode (will not deliver) - * citmail -i - Run as an SMTP daemon (typically from inetd) * */ @@ -339,6 +338,7 @@ void do_citmail(char recp[], int dtype) { time_t now; FILE *temp; int a; + int format_type = 0; char buf[128]; char from[512]; char userbuf[256]; @@ -347,6 +347,8 @@ void do_citmail(char recp[], int dtype) { char destsys[256]; char subject[256]; char targetroom[256]; + char content_type[256]; + char *extra_headers = NULL; if (dtype==REMOTE) { @@ -381,25 +383,56 @@ void do_citmail(char recp[], int dtype) { snprintf(buf, sizeof buf, "./network/spoolin/citmail.%d", getpid()); temp = fopen(buf,"w"); - putc(255,temp); putc(MES_NORMAL,temp); putc(1,temp); - strcpy(subject,""); + strcpy(subject, ""); strcpy(nodebuf, config.c_nodename); + strcpy(content_type, "text/plain"); + do { if (fgets(buf,128,stdin) == NULL) strcpy(buf, "."); strip_trailing_whitespace(buf); - if (!strncmp(buf,"Subject: ",9)) strcpy(subject,&buf[9]); - if (!strncmp(buf,"Date: ",6)) now = conv_date(&buf[6]); - if (!strncmp(buf,"From: ",6)) strcpy(from, &buf[6]); + if (!strncasecmp(buf,"Subject: ",9)) + strcpy(subject,&buf[9]); + else if (!strncasecmp(buf,"Date: ",6)) + now = conv_date(&buf[6]); + else if (!strncasecmp(buf,"From: ",6)) + strcpy(from, &buf[6]); + else if (!strncasecmp(buf,"Content-type: ",14)) + strcpy(content_type, &buf[14]); + else { + if (extra_headers == NULL) { + extra_headers = malloc(strlen(buf)+2); + strcpy(extra_headers, ""); + } + else { + extra_headers = realloc(extra_headers, + (strlen(extra_headers)+strlen(buf)+2)); + } + strcat(extra_headers, buf); + strcat(extra_headers, "\n"); + } } while ( (strcmp(buf, ".")) && (strcmp(buf, "")) ); process_rfc822_addr(from, userbuf, nodebuf, frombuf); + if (!strncasecmp(content_type, "text/plain", 10)) + format_type = 1; /* plain ASCII message */ + else + format_type = 4; /* MIME message */ + /* now convert it to Citadel format */ + + /* Header bytes */ + putc(255, temp); /* 0xFF = start-of-message byte */ + putc(MES_NORMAL, temp); /* Non-anonymous message */ + putc(format_type, temp); /* Format type */ + + /* Origination */ fprintf(temp,"P%s@%s%c", userbuf, nodebuf, 0); fprintf(temp,"T%ld%c", now, 0); fprintf(temp,"A%s%c", userbuf, 0); + /* Destination */ if (strlen(targetroom) > 0) { fprintf(temp, "O%s%c", targetroom, 0); } @@ -417,10 +450,18 @@ void do_citmail(char recp[], int dtype) { fprintf(temp,"R%s%c", recp, 0); } + /* Subject and text */ if (strlen(subject)>0) { fprintf(temp,"U%s%c", subject, 0); } putc('M',temp); + if (format_type == 4) { + fprintf(temp, "Content-type: %s\n", content_type); + if (extra_headers != NULL) + fprintf(temp, "%s", extra_headers); + fprintf(temp, "\n"); + } + if (extra_headers != NULL) free(extra_headers); if (strcmp(buf, ".")) loopcopy(temp, stdin); putc(0,temp); fclose(temp); @@ -513,7 +554,6 @@ int main(int argc, char **argv) { int is_test = 0; int deliver_to_ignet = 0; - int smtp = 0; static char recp[1024], buf[1024]; static char user[1024], node[1024], name[1024]; int a; @@ -526,160 +566,46 @@ int main(int argc, char **argv) is_test = 1; syslog(LOG_NOTICE,"test mode - will not deliver"); } - if (!strcmp(argv[1], "-i")) { - smtp = 1; - syslog(LOG_NOTICE,"started as an SMTP daemon"); - } - - if (smtp) { - strcpy(recp, ""); - } - else if (is_test == 0) { + if (is_test == 0) { strcpy(recp,argv[1]); } else { strcpy(recp,argv[2]); } - - if (smtp) { - /*** SMTP delivery mode ***/ - - printf("200 Citadel/UX SMTP gateway ready.\n"); + /*** Non-SMTP delivery mode ***/ + syslog(LOG_NOTICE,"recp: %s",recp); + for (a=0; a<2; ++a) { + alias(recp); + } - do { - fflush(stdout); - fflush(stderr); - fgets(buf, 1024, stdin); - while ( (strlen(buf)>0) && (buf[strlen(buf)-1]>0) && (buf[strlen(buf)-1]<32) ) { - buf[strlen(buf)-1] = 0; - } + /* did we alias it back to a remote address? */ + if ( (haschar(recp,'%')) + || (haschar(recp,'@')) + || (haschar(recp,'!')) ) { - /* null-pad to allow some lazy compares */ - buf[strlen(buf)+1] = 0; - buf[strlen(buf)+2] = 0; - buf[strlen(buf)+3] = 0; - - if (!strncasecmp(buf, "QUIT", 4)) { - printf("221 Later, dude.\n"); - } - else if (!strncasecmp(buf, "HELP", 4)) { - printf("214 You think _you_ need help?\n"); - } - else if (!strncasecmp(buf, "HELO", 4)) { - printf("250 Howdy ho, Mr. Hankey!\n"); - } - else if (!strncasecmp(buf, "MAIL", 4)) { - printf("250 Sure, whatever...\n"); - } - - - else if (!strncasecmp(buf, "RCPT To: ", 9)) { - if (strlen(recp) > 0) { - printf("571 Multiple recipients not supported.\n"); - } - else { - strcpy(recp, &buf[9]); - if (haschar(recp, ',')) { - printf("571 Multiple recipients not supported.\n"); - strcpy(recp, ""); - } - else { - syslog(LOG_NOTICE,"recp: %s",recp); - for (a=0; a<2; ++a) { - alias(recp); - } - - /* did we alias it back to a remote address? */ - if ( (haschar(recp,'%')) - || (haschar(recp,'@')) - || (haschar(recp,'!')) ) { + process_rfc822_addr(recp, user, node, name); + host_alias(node); - process_rfc822_addr(recp, user, node, name); - host_alias(node); - - /* If there are dots, it's an Internet host, so feed it - * back to an external mail transport agent such as sendmail. - */ - if (haschar(node, '.')) { - printf("571 Away with thee, spammer!\n"); - strcpy(recp, ""); - } - - /* Otherwise, we're dealing with Citadel mail. */ - else { - snprintf(recp, sizeof recp, "%s!%s", node, user); - deliver_to_ignet = 1; - printf("250 IGnet recipient.\n"); - } - } - else { - printf("250 Local recipient.\n"); - } - - } - - } - } - + /* If there are dots, it's an Internet host, so feed it + * back to an external mail transport agent such as sendmail. + */ + if (haschar(node, '.')) { + snprintf(buf, sizeof buf, SENDMAIL, recp); + system(buf); + exit(0); + } + /* Otherwise, we're dealing with Citadel mail. */ + else { + snprintf(recp, sizeof recp, "%s!%s", node, user); + deliver_to_ignet = 1; + } - else if (!strncasecmp(buf, "RCPT", 4)) { - printf("501 Only 'To:' commands are supported.\n"); - } - else if (!strncasecmp(buf, "DATA", 4)) { - if (strlen(recp) > 0) { - printf("354 Sock it to me, baby...\n"); - fflush(stdout); - deliver(recp, is_test, deliver_to_ignet); - printf("250 Cool beans!\n"); - } - else { - printf("503 No recipient has been specified.\n"); - } - } - else { - printf("500 Huh?\n"); - } - - } while (strncasecmp(buf,"QUIT",4)); } - else { - /*** Non-SMTP delivery mode ***/ - syslog(LOG_NOTICE,"recp: %s",recp); - for (a=0; a<2; ++a) { - alias(recp); - } - - /* did we alias it back to a remote address? */ - if ( (haschar(recp,'%')) - || (haschar(recp,'@')) - || (haschar(recp,'!')) ) { - - process_rfc822_addr(recp, user, node, name); - host_alias(node); - - /* If there are dots, it's an Internet host, so feed it - * back to an external mail transport agent such as sendmail. - */ - if (haschar(node, '.')) { - snprintf(buf, sizeof buf, SENDMAIL, recp); - system(buf); - exit(0); - } - - /* Otherwise, we're dealing with Citadel mail. */ - else { - snprintf(recp, sizeof recp, "%s!%s", node, user); - deliver_to_ignet = 1; - } - - } - - deliver(recp, is_test, deliver_to_ignet); - } + deliver(recp, is_test, deliver_to_ignet); if (RUN_NETPROC) execlp("./netproc", "netproc", "-i", NULL); exit(0); diff --git a/citadel/msgbase.c b/citadel/msgbase.c index fc594505e..257e03cee 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -357,7 +357,7 @@ time_t output_message(char *msgid, int mode, char lnode[256]; char mid[256]; time_t xtime = 0L; - /* */ + /* */ msg_num = atol(msgid); @@ -442,7 +442,7 @@ time_t output_message(char *msgid, int mode, /* now for the user-mode message reading loops */ cprintf("%d Message %ld:\n",LISTING_FOLLOWS,msg_num); - if (mode == MT_CITADEL) cprintf("type=%d\n",format_type); + if (mode == MT_CITADEL) cprintf("type=%d\n", format_type); if ( (anon_flag == MES_ANON) && (mode == MT_CITADEL) ) { cprintf("nhdr=yes\n"); @@ -553,9 +553,10 @@ time_t output_message(char *msgid, int mode, /* If the format type on disk is 1 (fixed-format), then we want * everything to be output completely literally ... regardless of - * what message transfer format is in use. + * what message transfer format is in use. Format type 4 is + * temporarily being output this way as well. */ - if (format_type == 1) { + if ( (format_type == 1) || (format_type == 4)) { strcpy(buf, ""); while(ch = *mptr++, ch>0) { if (ch == 13) ch = 10; @@ -602,7 +603,7 @@ void cmd_msg0(char *cmdbuf) headers_only = extract_int(cmdbuf, 1); desired_section = extract_int(cmdbuf, 2); - output_message(msgid,MT_CITADEL, headers_only, desired_section); + output_message(msgid, MT_CITADEL, headers_only, desired_section); return; } diff --git a/citadel/netproc.c b/citadel/netproc.c index 614cbccb4..630254b1e 100644 --- a/citadel/netproc.c +++ b/citadel/netproc.c @@ -74,23 +74,6 @@ struct syslist { char s_gdom[64]; }; -struct minfo { - char A[512]; - char E[512]; - long I; - char N[512]; - char O[512]; - char R[512]; - long T; - char D[512]; - char C[512]; - char nexthop[512]; - char H[512]; - char S[512]; - char B[512]; - char G[512]; - }; - void attach_to_server(int argc, char **argv); void serv_read(char *buf, int bytes); diff --git a/citadel/techdoc/hack.txt b/citadel/techdoc/hack.txt index 786cea829..fa757ed2a 100644 --- a/citadel/techdoc/hack.txt +++ b/citadel/techdoc/hack.txt @@ -42,20 +42,27 @@ one by one and sending them to the client for display, printing, or whatever. Implementing the "new message" function is also trivial in principle: we just keep track, for each caller in the userlog, of the highest-numbered -message which existed on the >last< call. (Remember, message numbers are +message which existed on the *last* call. (Remember, message numbers are simply assigned sequentially each time a message is created. This sequence is global to the entire system, not local within a room.) If we ignore all message-numbers in the room less than this, only new messages will be printed. Voila! - + + Message format on disk (MSGMAIN) - Each message begins with an FF byte. The next byte will then be MES_NORMAL, -MES_ANON, or MES_ANON2, depending on whether the message in anonymous or not. -The next byte is either a 0 or 1. If it is 0, the message will be printed -with the Citadel formatter. If it is a 1, the -message is printed directly to the screen, as is. External editors generate -this type of message. After these three opening bytes, the remainder of + As discussed above, each message begins with an FF byte. + + The next byte denotes whether this is an anonymous message. The codes +available are MES_NORMAL, MES_ANON, or MES_AN2 (defined in citadel.h). + + The third byte is a "message type" code. The following codes are defined: + 0 - "Traditional" Citadel format. Message is to be displayed "formatted." + 1 - Plain pre-formatted ASCII text (otherwise known as text/plain) + 4 - MIME formatted message. The text of the message which follows is + expected to begin with a "Content-type:" header. + + After these three opening bytes, the remainder of the message consists of a sequence of character strings. Each string begins with a type byte indicating the meaning of the string and is ended with a null. All strings are printable ASCII: in particular, @@ -70,10 +77,6 @@ all software should be written to IGNORE fields not currently defined. BYTE Mnemonic Comments -# Local ID A 32-bit integer containing the message ID on the - system the message is *currently* on (obviously this - is meaningless for a message being transmitted over - a network). A Author Name of originator of message. B Phone number The dialup number of the system this message originated on. This is optional, and is only @@ -110,11 +113,6 @@ T Date/Time A 32-bit integer containing the date and time of U Subject Optional. Developers may choose whether they wish to generate or display subject fields. Citadel/UX does not generate them, but it does print them when found. -X eXtension field Extension fields are used to carry additional RFC822 - type lines. X fields contain the X byte followed by - the RFC822 field name, a colon, a space, and the value. -Z Boundary If there are MIME attachments following the message - text, the Z field specifies the boundary string. EXAMPLE @@ -176,7 +174,7 @@ please see network.txt on its operation and functionality (if any). Portability issues - At this point, most hardware-dependent stuff has been removed from the + At this point, all hardware-dependent stuff has been removed from the system. On the server side, most of the OS-dependent stuff has been isolated into the sysdep.c source module. The server should compile on any POSIX compliant system with a full pthreads implementation and TCP/IP support. In @@ -205,7 +203,7 @@ struct quickroom { char QRpasswd[10]; /* Only valid if it's a private rm */ long QRroomaide; /* User number of room aide */ long QRhighest; /* Highest message NUMBER in room */ - char QRgen; /* Generation number of room */ + long QRgen; /* Generation number of room */ unsigned QRflags; /* See flag values below */ char QRdirname[15]; /* Directory name, if applicable */ char QRfloor; /* (not yet implemented) */ @@ -438,14 +436,16 @@ the room to be skipped. Very simple. SUPPORTING PRIVATE MAIL -Can one have an elegant kludge? This must come pretty close. - -Private mail is sent and recieved in the Mail> room, which otherwise -behaves pretty much as any other room. To make this work, we store -the actual message pointers in a message list for each user (MAILBOXES) -instead of MSGLISTS. This requires a little fiddling to get things just -right. We have to update quickroom[1].QRhighest at login -to reflect the presence or absence of new messages, for example. And + Can one have an elegant kludge? This must come pretty close. + + Private mail is sent and recieved in the Mail> room, which otherwise +behaves pretty much as any other room. To make this work, we have a +separate Mail> room for each user behind the scenes. The actual room name +in the database looks like "0000001234.Mail" (where '1234' is the user +number) and it's flagged with the QR_MAILBOX flag. The user number is +stripped off by the server before the name is presented to the client. + + This requires a little fiddling to get things just right. For example, make_message() has to be kludged to ask for the name of the recipient of the message whenever a message is entered in Mail>. But basically it works pretty well, keeping the code and user interface simple and diff --git a/citadel/techdoc/session.txt b/citadel/techdoc/session.txt index 47b0a4183..1994dd8a5 100644 --- a/citadel/techdoc/session.txt +++ b/citadel/techdoc/session.txt @@ -408,15 +408,17 @@ it's not there, the request is denied. LISTING_FOLLOWS code will be returned, followed by the contents of the message. The following fields may be sent: - type= Formatting type. Currently, there are two defined types. Type 0 is -"traditional" Citadel formatting. This means that newlines should be treated -as spaces UNLESS the first character on the next line is a space. In other -words, only indented lines should generate a newline on the user's screen when -the message is being displayed. This allows a message to be formatted to the -reader's screen width. It also allows the use of proportional fonts. -Type 1 is a simple fixed-format message. The message should be displayed to + type= Formatting type. The currently defined types are: + 0 = "traditional" Citadel formatting. This means that newlines should be +treated as spaces UNLESS the first character on the next line is a space. In +other words, only indented lines should generate a newline on the user's screen +when the message is being displayed. This allows a message to be formatted to +the reader's screen width. It also allows the use of proportional fonts. + 1 = a simple fixed-format message. The message should be displayed to the user's screen as is, preferably in a fixed-width font that will fit 80 columns on a screen. + 4 = MIME format message. The message text is expected to contain a header +with the "Content-type:" directive (and possibly others). msgn= The message ID of this message on the system it originated on. path= An e-mailable path back to the user who wrote the message. -- 2.30.2