]> 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 fe78592880f2579947df6272b069b8c32dc1f07f..34a96804776b1b7ca620112d186ef62fc6d9f05b 100644 (file)
@@ -1,7 +1,5 @@
 /* $Id$ */
 
-#define SMTP_PORT      2525
-
 #include "sysdep.h"
 #include <stdlib.h>
 #include <unistd.h>
@@ -30,6 +28,7 @@
 #include "msgbase.h"
 #include "tools.h"
 #include "internet_addressing.h"
+#include "genstamp.h"
 
 
 struct citsmtp {               /* Information about the current session */
@@ -38,28 +37,39 @@ struct citsmtp {            /* Information about the current session */
        int vrfy_count;
        char vrfy_match[256];
        char from[256];
-       char recipient[256];
        int number_of_recipients;
+       int delivery_mode;
 };
 
+
 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
+};
 
-long SYM_SMTP;
+#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);
@@ -135,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");
@@ -326,51 +338,113 @@ 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");
                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);
+       strcpy(recp, &argbuf[3]);
+       striplt(recp);
+       alias(recp);
+
+       cvt = convert_internet_address(user, node, recp);
+       sprintf(recp, "%s@%s", user, node);
+
 
-       cvt = convert_internet_address(user, node, SMTP->recipient);
        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", SMTP->recipient);
-                       strcpy(SMTP->recipient, "");
+                       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;
        }
 
-       strcpy(SMTP->recipient, "");
-       cprintf("599 Unknown error (FIX)\n");
+       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;
@@ -381,20 +455,48 @@ void smtp_data(void) {
                return;
        }
 
-*/
-
        cprintf("354 Transmit message now; terminate with '.' by itself\n");
-       body = CtdlReadMessageBody(".", config.c_maxmsglen);
+       
+       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;
        }
 
-       fprintf(stderr, "Converting message...\n");
+       lprintf(9, "Converting message...\n");
        msg = convert_internet_message(body);
 
-       phree(body);
-       cprintf("599 command unfinished\n");
+       /* 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");
+       }
 }
 
 
@@ -475,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$";
 }
+