]> code.citadel.org Git - citadel.git/blobdiff - citadel/serv_smtp.c
* Reworked some of the data structures to handle multiple recipients
[citadel.git] / citadel / serv_smtp.c
index 5d2136b559c19ab31a84d230091c01f047e59c7d..34a96804776b1b7ca620112d186ef62fc6d9f05b 100644 (file)
@@ -1,7 +1,5 @@
 /* $Id$ */
 
-#define SMTP_PORT      2525
-
 #include "sysdep.h"
 #include <stdlib.h>
 #include <unistd.h>
 #include "msgbase.h"
 #include "tools.h"
 #include "internet_addressing.h"
+#include "genstamp.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];
+       int number_of_recipients;
+       int delivery_mode;
 };
 
-enum {
+
+enum {                         /* Command states for login authentication */
        smtp_command,
        smtp_user,
        smtp_password
 };
 
-#define SMTP ((struct citsmtp *)CtdlGetUserData(SYM_SMTP))
+enum {                         /* Delivery modes */
+       smtp_deliver_local,
+       smtp_deliver_remote
+};
+
+#define SMTP           ((struct citsmtp *)CtdlGetUserData(SYM_SMTP))
+#define SMTP_RECP      ((char *)CtdlGetUserData(SYM_SMTP_RECP))
 
 long SYM_SMTP;
-
+long SYM_SMTP_RECP;
 
 /*
  * Here's where our SMTP session begins its happy day.
  */
 void smtp_greeting(void) {
 
-       strcpy(CC->cs_clientname, "Citadel SMTP");
+       strcpy(CC->cs_clientname, "SMTP session");
+       CC->internal_pgm = 1;
+       CC->cs_flags |= CS_STEALTH;
        CtdlAllocUserData(SYM_SMTP, sizeof(struct citsmtp));
+       CtdlAllocUserData(SYM_SMTP_RECP, 256);
+       sprintf(SMTP_RECP, "%s", "");
 
        cprintf("220 Welcome to the Citadel/UX ESMTP server at %s\n",
                config.c_fqdn);
@@ -85,6 +98,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");
@@ -131,6 +145,8 @@ void smtp_get_pass(char *argbuf) {
        if (CtdlTryPassword(password) == pass_ok) {
                cprintf("235 Authentication successful.\n");
                lprintf(9, "SMTP auth login successful\n");
+               CC->internal_pgm = 0;
+               CC->cs_flags &= ~CS_STEALTH;
        }
        else {
                cprintf("500 Authentication failed.\n");
@@ -305,6 +321,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,6 +335,11 @@ void smtp_mail(char *argbuf) {
  * Implements the "RCPT To:" command
  */
 void smtp_rcpt(char *argbuf) {
+       int cvt;
+       char user[256];
+       char node[256];
+       char recp[256];
+       int is_spam = 0;        /* FIX implement anti-spamming */
 
        if (strlen(SMTP->from) == 0) {
                cprintf("503 MAIL first, then RCPT.  Duh.\n");
@@ -329,7 +351,152 @@ void smtp_rcpt(char *argbuf) {
                return;
        }
 
-       cprintf("599 this is unfinished\n");
+       strcpy(recp, &argbuf[3]);
+       striplt(recp);
+       alias(recp);
+
+       cvt = convert_internet_address(user, node, recp);
+       sprintf(recp, "%s@%s", user, node);
+
+
+       switch(cvt) {
+               case rfc822_address_locally_validated:
+                       cprintf("250 %s is a valid recipient.\n", user);
+                       ++SMTP->number_of_recipients;
+                       CtdlReallocUserData(SYM_SMTP_RECP,
+                               strlen(SMTP_RECP) + 1024 );
+                       strcat(SMTP_RECP, "local|");
+                       strcat(SMTP_RECP, user);
+                       strcat(SMTP_RECP, "|0\n");
+                       return;
+
+               case rfc822_no_such_user:
+                       cprintf("550 %s: no such user\n", recp);
+                       return;
+
+               case rfc822_address_invalid:
+                       if (is_spam) {
+                               cprintf("551 Away with thee, spammer!\n");
+                       }
+                       else {
+                               cprintf("250 Remote recipient %s ok\n", recp);
+                               ++SMTP->number_of_recipients;
+                               CtdlReallocUserData(SYM_SMTP_RECP,
+                                       strlen(SMTP_RECP) + 1024 );
+                               strcat(SMTP_RECP, "remote|");
+                               strcat(SMTP_RECP, recp);
+                               strcat(SMTP_RECP, "|0\n");
+                               return;
+                       }
+                       return;
+       }
+
+       cprintf("599 Unknown error\n");
+}
+
+
+
+
+
+/*
+ * Back end for smtp_data()  ... this does the actual delivery of the message
+ * Returns 0 on success, nonzero on failure
+ */
+int smtp_message_delivery(struct CtdlMessage *msg) {
+       char user[256];
+       char node[256];
+       char name[256];
+       int successful_saves = 0;
+       int failed_saves = 0;
+       long msgid = (-1L);
+
+       lprintf(9, "smtp_message_delivery() called\n");
+
+       /* Fill in 'from' fields with envelope information if missing */
+       process_rfc822_addr(SMTP->from, user, node, name);
+       if (msg->cm_fields['A']==NULL) msg->cm_fields['A'] = strdoop(user);
+       if (msg->cm_fields['N']==NULL) msg->cm_fields['N'] = strdoop(node);
+       if (msg->cm_fields['H']==NULL) msg->cm_fields['H'] = strdoop(name);
+
+       /* Save the message in the queue */
+       msgid = CtdlSaveMsg(msg,
+               "",
+               SMTP_SPOOLOUT_ROOM,
+               MES_LOCAL,
+               1);
+       ++successful_saves;
+
+               /* FIX go thru each local user and save to boxes
+                       then stuff remote users in queue list
+                       then delete from queue if num remote users is 0
+               */
+
+       return(failed_saves);
+}
+
+
+
+/*
+ * Implements the DATA command
+ */
+void smtp_data(void) {
+       char *body;
+       struct CtdlMessage *msg;
+       int retval;
+       char nowstamp[256];
+
+       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");
+       
+       generate_rfc822_datestamp(nowstamp, time(NULL));
+       body = mallok(4096);
+       if (body != NULL) sprintf(body,
+               "Received: from %s\n"
+               "       by %s;\n"
+               "       %s\n",
+                       "FIX.FIX.com",
+                       config.c_fqdn,
+                       nowstamp);
+       
+       body = CtdlReadMessageBody(".", config.c_maxmsglen, body);
+       if (body == NULL) {
+               cprintf("550 Unable to save message text: internal error.\n");
+               return;
+       }
+
+       lprintf(9, "Converting message...\n");
+       msg = convert_internet_message(body);
+
+       /* If the user is locally authenticated, FORCE the From: header to
+        * show up as the real sender
+        */
+       if (CC->logged_in) {
+               if (msg->cm_fields['A'] != NULL) phree(msg->cm_fields['A']);
+               if (msg->cm_fields['N'] != NULL) phree(msg->cm_fields['N']);
+               if (msg->cm_fields['H'] != NULL) phree(msg->cm_fields['H']);
+               msg->cm_fields['A'] = strdoop(CC->usersupp.fullname);
+               msg->cm_fields['N'] = strdoop(config.c_nodename);
+               msg->cm_fields['H'] = strdoop(config.c_humannode);
+       }
+
+       retval = smtp_message_delivery(msg);
+       CtdlFreeMessage(msg);
+
+       if (!retval) {
+               cprintf("250 Message accepted for delivery.\n");
+       }
+       else {
+               cprintf("550 Internal error.\n");
+       }
 }
 
 
@@ -363,6 +530,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);
        }
@@ -406,18 +577,20 @@ void smtp_command_loop(void) {
        }
 
        else {
-               cprintf("500 I'm afraid I can't do that, Dave.\n");
+               cprintf("502 I'm afraid I can't do that, Dave.\n");
        }
 
 }
 
 
-
 char *Dynamic_Module_Init(void)
 {
        SYM_SMTP = CtdlGetDynamicSymbol();
+       SYM_SMTP_RECP = CtdlGetDynamicSymbol();
        CtdlRegisterServiceHook(SMTP_PORT,
                                smtp_greeting,
                                smtp_command_loop);
+       create_room(SMTP_SPOOLOUT_ROOM, 3, "", 0);
        return "$Id$";
 }
+