From 702056162c085dd550b7a4d96a15555b1c4dda62 Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Tue, 14 Dec 1999 23:20:00 +0000 Subject: [PATCH] * More SMTP implementation --- citadel/internet_addressing.c | 48 ++++++++++++-- citadel/internet_addressing.h | 9 +++ citadel/msgbase.c | 101 +++++++++++++++++------------- citadel/msgbase.h | 1 + citadel/parsedate.c | 114 ++++++++++++++-------------------- citadel/parsedate.y | 50 +++++---------- citadel/serv_smtp.c | 68 +++++++++++++++++++- citadel/tools.c | 4 +- 8 files changed, 242 insertions(+), 153 deletions(-) diff --git a/citadel/internet_addressing.c b/citadel/internet_addressing.c index 8881214d0..0612e77b2 100644 --- a/citadel/internet_addressing.c +++ b/citadel/internet_addressing.c @@ -59,6 +59,10 @@ void process_rfc822_addr(char *rfc822, char *user, char *node, char *name) { int a; + strcpy(user, ""); + strcpy(node, config.c_fqdn); + strcpy(name, ""); + /* extract full name - first, it's From minus */ strcpy(name, rfc822); for (a = 0; a < strlen(name); ++a) { @@ -204,6 +208,7 @@ void try_name(struct usersupp *us) { } + /* * Convert an Internet email address to a Citadel user/host combination */ @@ -228,7 +233,7 @@ int convert_internet_address(char *destuser, char *desthost, char *source) * FIX ... make this work for non-local systems */ if (strcasecmp(node, config.c_nodename)) { - return(1); + return(rfc822_address_invalid); } /* Now try to resolve the name @@ -240,10 +245,45 @@ int convert_internet_address(char *destuser, char *desthost, char *source) strcpy(CC->buffer1, user); strcpy(CC->buffer2, ""); ForEachUser(try_name); - if (strlen(CC->buffer2) == 0) return(2); + if (strlen(CC->buffer2) == 0) return(rfc822_no_such_user); strcpy(destuser, CC->buffer2); - return(0); + return(rfc822_address_locally_validated); + } + + return(rfc822_address_invalid); /* unknown error */ +} + + + + + +/* + * Convert an RFC822 message (headers + body) to a CtdlMessage structure. + */ +struct CtdlMessage *convert_internet_message(char *rfc822) { + + struct CtdlMessage *msg; + char *buf; + + msg = mallok(sizeof(struct CtdlMessage)); + if (msg == NULL) return msg; + + memset(msg, 0, sizeof(struct CtdlMessage)); + msg->cm_magic = CTDLMESSAGE_MAGIC; /* self check */ + msg->cm_anon_type = 0; /* never anonymous */ + msg->cm_format_type = 4; /* always MIME */ + msg->cm_fields['M'] = rfc822; + + /* FIX there's plenty to do here. */ + + + /* Follow-up sanity check. */ + + /* If there's no timestamp on this message, set it to now. */ + if (msg->cm_fields['T'] == NULL) { + sprintf(buf, "%ld", time(NULL)); + msg->cm_fields['T'] = strdoop(buf); } - return(3); /* unknown error */ + return msg; } diff --git a/citadel/internet_addressing.h b/citadel/internet_addressing.h index 917e22700..81913878b 100644 --- a/citadel/internet_addressing.h +++ b/citadel/internet_addressing.h @@ -1,3 +1,12 @@ int fuzzy_match(struct usersupp *us, char *matchstring); void process_rfc822_addr(char *rfc822, char *user, char *node, char *name); int convert_internet_address(char *destuser, char *desthost, char *source); + + +enum { + rfc822_address_locally_validated, + rfc822_no_such_user, + rfc822_address_on_citadel_network, + rfc822_address_invalid +}; + diff --git a/citadel/msgbase.c b/citadel/msgbase.c index 5b37783ff..045e38e86 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -1590,6 +1590,64 @@ void quickie_message(char *from, char *to, char *room, char *text) } + +/* + * Back end function used by make_message() and similar functions + */ +char *CtdlReadMessageBody(char *terminator, size_t maxlen) { + char buf[256]; + size_t message_len = 0; + size_t buffer_len = 0; + char *ptr, *append; + char *m; + + m = mallok(4096); + if (m == NULL) { + while ( (client_gets(buf)>0) && strcmp(buf, terminator) ) ;; + return(NULL); + } else { + buffer_len = 4096; + m[0] = 0; + message_len = 0; + } + /* read in the lines of message text one by one */ + append = NULL; + while ( (client_gets(buf)>0) && strcmp(buf, terminator) ) { + + /* augment the buffer if we have to */ + if ((message_len + strlen(buf) + 2) > buffer_len) { + lprintf(9, "realloking\n"); + ptr = reallok(m, (buffer_len * 2) ); + if (ptr == NULL) { /* flush if can't allocate */ + while ( (client_gets(buf)>0) && + strcmp(buf, terminator)) ;; + return(m); + } else { + buffer_len = (buffer_len * 2); + m = ptr; + append = NULL; + lprintf(9, "buffer_len is %d\n", buffer_len); + } + } + + if (append == NULL) append = m; + while (strlen(append) > 0) ++append; + strcpy(append, buf); + strcat(append, "\n"); + message_len = message_len + strlen(buf) + 1; + + /* if we've hit the max msg length, flush the rest */ + if (message_len >= maxlen) { + while ( (client_gets(buf)>0) && strcmp(buf, terminator)) ;; + return(m); + } + } + return(m); +} + + + + /* * Build a binary message to be saved on disk. */ @@ -1607,9 +1665,6 @@ struct CtdlMessage *make_message( int a; char dest_node[32]; char buf[256]; - size_t message_len = 0; - size_t buffer_len = 0; - char *ptr, *append; struct CtdlMessage *msg; msg = mallok(sizeof(struct CtdlMessage)); @@ -1664,47 +1719,9 @@ struct CtdlMessage *make_message( if (dest_node[0] != 0) msg->cm_fields['D'] = strdoop(dest_node); - msg->cm_fields['M'] = mallok(4096); - if (msg->cm_fields['M'] == NULL) { - while (client_gets(buf), strcmp(buf, "000")) ;; /* flush */ - return(msg); - } else { - buffer_len = 4096; - msg->cm_fields['M'][0] = 0; - message_len = 0; - } - /* read in the lines of message text one by one */ - append = NULL; - while (client_gets(buf), strcmp(buf, "000")) { + msg->cm_fields['M'] = CtdlReadMessageBody("000", config.c_maxmsglen); - /* augment the buffer if we have to */ - if ((message_len + strlen(buf) + 2) > buffer_len) { - lprintf(9, "realloking\n"); - ptr = reallok(msg->cm_fields['M'], (buffer_len * 2) ); - if (ptr == NULL) { /* flush if can't allocate */ - while (client_gets(buf), strcmp(buf, "000")) ;; - return(msg); - } else { - buffer_len = (buffer_len * 2); - msg->cm_fields['M'] = ptr; - append = NULL; - lprintf(9, "buffer_len is %d\n", buffer_len); - } - } - - if (append == NULL) append = msg->cm_fields['M']; - while (strlen(append) > 0) ++append; - strcpy(append, buf); - strcat(append, "\n"); - message_len = message_len + strlen(buf) + 1; - - /* if we've hit the max msg length, flush the rest */ - if (message_len >= config.c_maxmsglen) { - while (client_gets(buf), strcmp(buf, "000")) ;; - return(msg); - } - } return(msg); } diff --git a/citadel/msgbase.h b/citadel/msgbase.h index 471885119..8193b90d5 100644 --- a/citadel/msgbase.h +++ b/citadel/msgbase.h @@ -70,3 +70,4 @@ void serialize_message(struct ser_ret *, struct CtdlMessage *); int is_valid_message(struct CtdlMessage *); int ReplicationChecks(struct CtdlMessage *); int CtdlSaveMsgPointerInRoom(char *roomname, long msgid, int flags); +char *CtdlReadMessageBody(char *terminator, size_t maxlen); diff --git a/citadel/parsedate.c b/citadel/parsedate.c index f813214de..e25be1173 100644 --- a/citadel/parsedate.c +++ b/citadel/parsedate.c @@ -17,7 +17,8 @@ static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; ** and Jim Berets in August, 1990. ** Further revised (removed obsolete constructs and cleaned up timezone ** names) in August, 1991, by Rich. Paul Eggert -** helped in September, 1992. +** helped in September, 1992. Art Cancro cleaned +** it up for ANSI C in December, 1999. ** ** This grammar has six shift/reduce conflicts. ** @@ -32,7 +33,7 @@ static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; #include #include -int date_lex(); +int date_lex(void); #define yyparse date_parse #define yylex date_lex @@ -102,15 +103,13 @@ static time_t yyRelMonth; static time_t yyRelSeconds; -extern struct tm *localtime(); - -static void date_error(); -#line 100 "parsedate.y" +static void date_error(char *); +#line 99 "parsedate.y" typedef union { time_t Number; enum _MERIDIAN Meridian; } YYSTYPE; -#line 114 "y.tab.c" +#line 113 "y.tab.c" #define tDAY 257 #define tDAYZONE 258 #define tMERIDIAN 259 @@ -294,7 +293,7 @@ YYSTYPE yylval; short yyss[YYSTACKSIZE]; YYSTYPE yyvs[YYSTACKSIZE]; #define yystacksize YYSTACKSIZE -#line 287 "parsedate.y" +#line 286 "parsedate.y" /* Month and day table. */ static TABLE MonthDayTable[] = { @@ -457,11 +456,7 @@ date_error(s) static time_t -ToSeconds(Hours, Minutes, Seconds, Meridian) - time_t Hours; - time_t Minutes; - time_t Seconds; - MERIDIAN Meridian; +ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian) { if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61) return -1; @@ -482,15 +477,9 @@ ToSeconds(Hours, Minutes, Seconds, Meridian) static time_t -Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, dst) - time_t Month; - time_t Day; - time_t Year; - time_t Hours; - time_t Minutes; - time_t Seconds; - MERIDIAN Meridian; - DSTMODE dst; +Convert(time_t Month, time_t Day, time_t Year, + time_t Hours, time_t Minutes, time_t Seconds, + MERIDIAN Meridian, DSTMODE dst) { static int DaysNormal[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 @@ -544,9 +533,7 @@ Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, dst) static time_t -DSTcorrect(Start, Future) - time_t Start; - time_t Future; +DSTcorrect(time_t Start, time_t Future) { time_t StartDay; time_t FutureDay; @@ -558,9 +545,7 @@ DSTcorrect(Start, Future) static time_t -RelativeMonth(Start, RelMonth) - time_t Start; - time_t RelMonth; +RelativeMonth(time_t Start, time_t RelMonth) { struct tm *tm; time_t Month; @@ -578,9 +563,7 @@ RelativeMonth(Start, RelMonth) static int -LookupWord(buff, length) - char *buff; - register int length; +LookupWord(char *buff, register int length) { register char *p; register char *q; @@ -670,7 +653,7 @@ LookupWord(buff, length) int -date_lex() +date_lex(void) { register char c; register char *p; @@ -733,10 +716,9 @@ date_lex() time_t -parsedate(p) - char *p; +parsedate(char *p) { - extern int date_parse(); + extern int date_parse(void); time_t Start; yyInput = p; @@ -786,9 +768,7 @@ extern int yydebug; /* ARGSUSED */ int -main(ac, av) - int ac; - char *av[]; +main(int ac, char *av[]) { char buff[128]; time_t d; @@ -821,7 +801,7 @@ main(ac, av) /* NOTREACHED */ } #endif /* TEST */ -#line 825 "y.tab.c" +#line 805 "y.tab.c" #define YYABORT goto yyabort #define YYREJECT goto yyabort #define YYACCEPT goto yyaccept @@ -963,7 +943,7 @@ yyreduce: switch (yyn) { case 3: -#line 118 "parsedate.y" +#line 117 "parsedate.y" { yyHaveTime++; #ifdef lint @@ -975,26 +955,26 @@ case 3: } break; case 4: -#line 127 "parsedate.y" +#line 126 "parsedate.y" { yyHaveTime++; yyTimezone = yyvsp[0].Number; } break; case 5: -#line 131 "parsedate.y" +#line 130 "parsedate.y" { yyHaveDate++; } break; case 6: -#line 134 "parsedate.y" +#line 133 "parsedate.y" { yyHaveRel = 1; } break; case 7: -#line 139 "parsedate.y" +#line 138 "parsedate.y" { if (yyvsp[-1].Number < 100) { yyHour = yyvsp[-1].Number; @@ -1009,7 +989,7 @@ case 7: } break; case 8: -#line 151 "parsedate.y" +#line 150 "parsedate.y" { yyHour = yyvsp[-3].Number; yyMinutes = yyvsp[-1].Number; @@ -1018,7 +998,7 @@ case 8: } break; case 9: -#line 157 "parsedate.y" +#line 156 "parsedate.y" { yyHour = yyvsp[-3].Number; yyMinutes = yyvsp[-1].Number; @@ -1028,7 +1008,7 @@ case 9: } break; case 10: -#line 164 "parsedate.y" +#line 163 "parsedate.y" { yyHour = yyvsp[-5].Number; yyMinutes = yyvsp[-3].Number; @@ -1037,7 +1017,7 @@ case 10: } break; case 11: -#line 170 "parsedate.y" +#line 169 "parsedate.y" { yyHour = yyvsp[-5].Number; yyMinutes = yyvsp[-3].Number; @@ -1048,21 +1028,21 @@ case 11: } break; case 12: -#line 180 "parsedate.y" +#line 179 "parsedate.y" { yyval.Number = yyvsp[0].Number; yyDSTmode = DSToff; } break; case 13: -#line 184 "parsedate.y" +#line 183 "parsedate.y" { yyval.Number = yyvsp[0].Number; yyDSTmode = DSTon; } break; case 14: -#line 188 "parsedate.y" +#line 187 "parsedate.y" { /* Only allow "GMT+300" and "GMT-0800" */ if (yyvsp[-1].Number != 0) { @@ -1073,14 +1053,14 @@ case 14: } break; case 15: -#line 196 "parsedate.y" +#line 195 "parsedate.y" { yyval.Number = yyvsp[0].Number; yyDSTmode = DSToff; } break; case 16: -#line 202 "parsedate.y" +#line 201 "parsedate.y" { int i; @@ -1102,14 +1082,14 @@ case 16: } break; case 17: -#line 223 "parsedate.y" +#line 222 "parsedate.y" { yyMonth = yyvsp[-2].Number; yyDay = yyvsp[0].Number; } break; case 18: -#line 227 "parsedate.y" +#line 226 "parsedate.y" { if (yyvsp[-4].Number > 100) { yyYear = yyvsp[-4].Number; @@ -1124,14 +1104,14 @@ case 18: } break; case 19: -#line 239 "parsedate.y" +#line 238 "parsedate.y" { yyMonth = yyvsp[-1].Number; yyDay = yyvsp[0].Number; } break; case 20: -#line 243 "parsedate.y" +#line 242 "parsedate.y" { yyMonth = yyvsp[-3].Number; yyDay = yyvsp[-2].Number; @@ -1139,14 +1119,14 @@ case 20: } break; case 21: -#line 248 "parsedate.y" +#line 247 "parsedate.y" { yyDay = yyvsp[-1].Number; yyMonth = yyvsp[0].Number; } break; case 22: -#line 252 "parsedate.y" +#line 251 "parsedate.y" { yyDay = yyvsp[-2].Number; yyMonth = yyvsp[-1].Number; @@ -1154,7 +1134,7 @@ case 22: } break; case 23: -#line 257 "parsedate.y" +#line 256 "parsedate.y" { yyDay = yyvsp[-2].Number; yyMonth = yyvsp[-1].Number; @@ -1162,42 +1142,42 @@ case 23: } break; case 24: -#line 264 "parsedate.y" +#line 263 "parsedate.y" { yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; } break; case 25: -#line 267 "parsedate.y" +#line 266 "parsedate.y" { yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; } break; case 26: -#line 270 "parsedate.y" +#line 269 "parsedate.y" { yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; } break; case 27: -#line 273 "parsedate.y" +#line 272 "parsedate.y" { yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; } break; case 28: -#line 278 "parsedate.y" +#line 277 "parsedate.y" { yyval.Meridian = MER24; } break; case 29: -#line 281 "parsedate.y" +#line 280 "parsedate.y" { yyval.Meridian = yyvsp[0].Meridian; } break; -#line 1201 "y.tab.c" +#line 1181 "y.tab.c" } yyssp -= yym; yystate = *yyssp; diff --git a/citadel/parsedate.y b/citadel/parsedate.y index e167f59b7..5663c6d21 100644 --- a/citadel/parsedate.y +++ b/citadel/parsedate.y @@ -7,7 +7,8 @@ ** and Jim Berets in August, 1990. ** Further revised (removed obsolete constructs and cleaned up timezone ** names) in August, 1991, by Rich. Paul Eggert -** helped in September, 1992. +** helped in September, 1992. Art Cancro cleaned +** it up for ANSI C in December, 1999. ** ** This grammar has six shift/reduce conflicts. ** @@ -22,7 +23,7 @@ #include #include -int date_lex(); +int date_lex(void); #define yyparse date_parse #define yylex date_lex @@ -92,9 +93,7 @@ static time_t yyRelMonth; static time_t yyRelSeconds; -extern struct tm *localtime(); - -static void date_error(); +static void date_error(char *); %} %union { @@ -446,11 +445,7 @@ date_error(s) static time_t -ToSeconds(Hours, Minutes, Seconds, Meridian) - time_t Hours; - time_t Minutes; - time_t Seconds; - MERIDIAN Meridian; +ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian) { if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61) return -1; @@ -471,15 +466,9 @@ ToSeconds(Hours, Minutes, Seconds, Meridian) static time_t -Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, dst) - time_t Month; - time_t Day; - time_t Year; - time_t Hours; - time_t Minutes; - time_t Seconds; - MERIDIAN Meridian; - DSTMODE dst; +Convert(time_t Month, time_t Day, time_t Year, + time_t Hours, time_t Minutes, time_t Seconds, + MERIDIAN Meridian, DSTMODE dst) { static int DaysNormal[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 @@ -533,9 +522,7 @@ Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, dst) static time_t -DSTcorrect(Start, Future) - time_t Start; - time_t Future; +DSTcorrect(time_t Start, time_t Future) { time_t StartDay; time_t FutureDay; @@ -547,9 +534,7 @@ DSTcorrect(Start, Future) static time_t -RelativeMonth(Start, RelMonth) - time_t Start; - time_t RelMonth; +RelativeMonth(time_t Start, time_t RelMonth) { struct tm *tm; time_t Month; @@ -567,9 +552,7 @@ RelativeMonth(Start, RelMonth) static int -LookupWord(buff, length) - char *buff; - register int length; +LookupWord(char *buff, register int length) { register char *p; register char *q; @@ -659,7 +642,7 @@ LookupWord(buff, length) int -date_lex() +date_lex(void) { register char c; register char *p; @@ -722,10 +705,9 @@ date_lex() time_t -parsedate(p) - char *p; +parsedate(char *p) { - extern int date_parse(); + extern int date_parse(void); time_t Start; yyInput = p; @@ -775,9 +757,7 @@ extern int yydebug; /* ARGSUSED */ int -main(ac, av) - int ac; - char *av[]; +main(int ac, char *av[]) { char buff[128]; time_t d; diff --git a/citadel/serv_smtp.c b/citadel/serv_smtp.c index 5d2136b55..d370d03fe 100644 --- a/citadel/serv_smtp.c +++ b/citadel/serv_smtp.c @@ -31,15 +31,18 @@ #include "tools.h" #include "internet_addressing.h" -struct citsmtp { + +struct citsmtp { /* Information about the current session */ int command_state; struct usersupp vrfy_buffer; int vrfy_count; char vrfy_match[256]; char from[256]; + char recipient[256]; + int number_of_recipients; }; -enum { +enum { /* Command states for login authentication */ smtp_command, smtp_user, smtp_password @@ -85,6 +88,7 @@ void smtp_hello(char *argbuf, int is_esmtp) { */ void smtp_help(void) { cprintf("214-Here's the frequency, Kenneth:\n"); + cprintf("214- DATA\n"); cprintf("214- EHLO\n"); cprintf("214- EXPN\n"); cprintf("214- HELO\n"); @@ -305,6 +309,7 @@ void smtp_mail(char *argbuf) { if (!strcasecmp(node, config.c_nodename)) { /* FIX use fcn */ cprintf("550 You must log in to send mail from %s\n", config.c_fqdn); + strcpy(SMTP->from, ""); return; } } @@ -318,18 +323,71 @@ void smtp_mail(char *argbuf) { * Implements the "RCPT To:" command */ void smtp_rcpt(char *argbuf) { + int cvt; + char user[256]; + char node[256]; if (strlen(SMTP->from) == 0) { cprintf("503 MAIL first, then RCPT. Duh.\n"); return; } + if (strlen(SMTP->recipient) > 0) { + cprintf("550 Only one recipient allowed (FIX)\n"); + return; + } + if (strncasecmp(argbuf, "To:", 3)) { cprintf("501 Syntax error\n"); return; } - cprintf("599 this is unfinished\n"); + strcpy(SMTP->recipient, &argbuf[3]); + striplt(SMTP->recipient); + + cvt = convert_internet_address(user, node, SMTP->recipient); + switch(cvt) { + case rfc822_address_locally_validated: + cprintf("250 %s is a valid recipient.\n", user); + return; + case rfc822_no_such_user: + cprintf("550 %s: no such user\n", SMTP->recipient); + strcpy(SMTP->recipient, ""); + return; + } + + strcpy(SMTP->recipient, ""); + cprintf("599 Unknown error (FIX)\n"); +} + + + + +/* + * Implements the DATA command + */ +void smtp_data(void) { + char *body; + + if (strlen(SMTP->from) == 0) { + cprintf("503 Need MAIL command first.\n"); + return; + } + + if (SMTP->number_of_recipients < 1) { + cprintf("503 Need RCPT command first.\n"); + return; + } + + cprintf("354 Transmit message now; terminate with '.' by itself\n"); + body = CtdlReadMessageBody(".", config.c_maxmsglen); + if (body == NULL) { + cprintf("550 Unable to save message text: internal error.\n"); + return; + } + + phree(body); + cprintf("599 command unfinished\n"); } @@ -363,6 +421,10 @@ void smtp_command_loop(void) { smtp_auth(&cmdbuf[5]); } + else if (!strncasecmp(cmdbuf, "DATA", 4)) { + smtp_data(); + } + else if (!strncasecmp(cmdbuf, "EHLO", 4)) { smtp_hello(&cmdbuf[5], 1); } diff --git a/citadel/tools.c b/citadel/tools.c index 8117cf1d2..052122e66 100644 --- a/citadel/tools.c +++ b/citadel/tools.c @@ -260,13 +260,13 @@ int collapsed_strcmp(char *s1, char *s2) { c2 = strdup(s2); for (i=0; i