#include "database.h"
#include "msgbase.h"
#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
*/
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");
cprintf("214- HELP\n");
+ cprintf("214- MAIL\n");
cprintf("214- NOOP\n");
cprintf("214- QUIT\n");
+ cprintf("214- RCPT\n");
+ cprintf("214- RSET\n");
cprintf("214- VRFY\n");
cprintf("214 I could tell you more, but then I'd have to kill you.\n");
}
}
-/*
- * Return 0 if a given string fuzzy-matches a Citadel user account
- *
- * FIX ... this needs to be updated to match any and all ways of addressing
- * a user. It may even be appropriate to move this out of SMTP and
- * into the server core.
- */
-int fuzzy_match(struct usersupp *us, char *matchstring) {
- int a;
-
- for (a=0; a<strlen(us->fullname); ++a) {
- if (!strncasecmp(&us->fullname[a],
- matchstring, strlen(matchstring))) {
- return 0;
- }
- }
- return -1;
-}
-
-
/*
* Back end for smtp_vrfy() command
*/
}
+/*
+ * Implements the RSET (reset state) command.
+ * Currently this just zeroes out the state buffer. If pointers to data
+ * allocated with mallok() are ever placed in the state buffer, we have to
+ * be sure to phree() them first!
+ */
+void smtp_rset(void) {
+ memset(SMTP, 0, sizeof(struct citsmtp));
+ if (CC->logged_in) logout(CC);
+ cprintf("250 Zap!\n");
+}
+
+
+
+/*
+ * Implements the "MAIL From:" command
+ */
+void smtp_mail(char *argbuf) {
+ char user[256];
+ char node[256];
+ int cvt;
+
+ if (strlen(SMTP->from) != 0) {
+ cprintf("503 Only one sender permitted\n");
+ return;
+ }
+
+ if (strncasecmp(argbuf, "From:", 5)) {
+ cprintf("501 Syntax error\n");
+ return;
+ }
+
+ strcpy(SMTP->from, &argbuf[5]);
+ striplt(SMTP->from);
+
+ if (strlen(SMTP->from) == 0) {
+ cprintf("501 Empty sender name is not permitted\n");
+ return;
+ }
+
+
+ /* If this SMTP connection is from a logged-in user, make sure that
+ * the user only sends email from his/her own address.
+ */
+ if (CC->logged_in) {
+ cvt = convert_internet_address(user, node, SMTP->from);
+ lprintf(9, "cvt=%d, citaddr=<%s@%s>\n", cvt, user, node);
+ if ( (cvt != 0) || (strcasecmp(user, CC->usersupp.fullname))) {
+ cprintf("550 <%s> is not your address.\n", SMTP->from);
+ strcpy(SMTP->from, "");
+ return;
+ }
+ }
+
+ /* Otherwise, make sure outsiders aren't trying to forge mail from
+ * this system.
+ */
+ else {
+ cvt = convert_internet_address(user, node, SMTP->from);
+ lprintf(9, "cvt=%d, citaddr=<%s@%s>\n", cvt, user, node);
+ 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;
+ }
+ }
+
+ cprintf("250 Sender ok. Groovy.\n");
+}
+
+
+
+/*
+ * 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;
+ }
+
+ 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;
+ struct CtdlMessage *msg;
+
+/*
+ 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;
+ }
+
+ fprintf(stderr, "Converting message...\n");
+ msg = convert_internet_message(body);
+ phree(body);
+
+ CtdlSaveMsg(msg, "", BASEROOM, MES_LOCAL, 1); /* FIX temporary */
+ CtdlFreeMessage(msg);
+
+ cprintf("599 command unfinished but message saved\n");
+}
+
+
+
/*
* Main command loop for SMTP sessions.
smtp_auth(&cmdbuf[5]);
}
+ else if (!strncasecmp(cmdbuf, "DATA", 4)) {
+ smtp_data();
+ }
+
else if (!strncasecmp(cmdbuf, "EHLO", 4)) {
smtp_hello(&cmdbuf[5], 1);
}
smtp_help();
}
+ else if (!strncasecmp(cmdbuf, "MAIL", 4)) {
+ smtp_mail(&cmdbuf[5]);
+ }
+
else if (!strncasecmp(cmdbuf, "NOOP", 4)) {
cprintf("250 This command successfully did nothing.\n");
}
return;
}
+ else if (!strncasecmp(cmdbuf, "RCPT", 4)) {
+ smtp_rcpt(&cmdbuf[5]);
+ }
+
+ else if (!strncasecmp(cmdbuf, "RSET", 4)) {
+ smtp_rset();
+ }
+
else if (!strncasecmp(cmdbuf, "VRFY", 4)) {
smtp_vrfy(&cmdbuf[5]);
}