fix dlen
[citadel.git] / citadel / server / modules / smtp / serv_smtpclient.c
index edce1f5c387088008f16b42ca651860bb6d42dbb..03f54b108b0725c794e0fb2f6c5b8dcbf4bdd5ca 100644 (file)
@@ -2,7 +2,7 @@
 //
 // This is the new, exciting, clever version that makes libcurl do all the work  :)
 //
-// Copyright (c) 1997-2023 by the citadel.org team
+// Copyright (c) 1997-2024 by the citadel.org team
 //
 // This program is open source software.  Use, duplication, or disclosure
 // is subject to the terms of the GNU General Public License, version 3.
@@ -213,29 +213,52 @@ int smtp_attempt_delivery(long msgid, char *recp, char *envelope_from, char *sou
        process_rfc822_addr(recp, user, node, name);    // split recipient address into username, hostname, displayname
        num_mx = getmx(mxes, node);
        if (num_mx < 1) {
-               return (421);
+               return(421);
        }
 
        CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
+
+       // If we have a source room, it's probably a mailing list message; generate an unsubscribe header
        if (!IsEmptyStr(source_room)) {
-               // If we have a source room, it's probably a mailing list message; generate an unsubscribe header
-               char esc_room[ROOMNAMELEN*2];
-               char esc_email[1024];
-               urlesc(esc_room, sizeof esc_room, source_room);
-               urlesc(esc_email, sizeof esc_email, recp);
-               cprintf("List-Unsubscribe: <http://%s/listsub?cmd=unsubscribe&room=%s&email=%s>\r\n",
-                       CtdlGetConfigStr("c_fqdn"),
-                       esc_room,
-                       esc_email
-               );
+               char base_url[SIZ];
+               char unsubscribe_url[SIZ];
+               snprintf(base_url, sizeof base_url, "https://%s/listsub", CtdlGetConfigStr("c_fqdn"));
+               generate_one_click_url(unsubscribe_url, base_url, "unsubscribe", source_room, recp);
+               cprintf("List-Unsubscribe: %s\r\n", unsubscribe_url);
+               cprintf("List-Unsubscribe-Post: List-Unsubscribe=One-Click\r\n");       // RFC 8058
+
        }
+
        CtdlOutputMsg(msgid, MT_RFC822, HEADERS_ALL, 0, 1, NULL, 0, NULL, &fromaddr, NULL);
        s.TheMessage = CC->redirect_buffer;
-       s.bytes_total = StrLength(CC->redirect_buffer);
-       s.bytes_sent = 0;
        CC->redirect_buffer = NULL;
+       syslog(LOG_DEBUG, "fromaddr=<%s>",fromaddr);
+
+       // If we have a DKIM key, try to sign the message.
+       char *dkim_private_key = CtdlGetConfigStr("dkim_private_key");
+       char *dkim_selector = CtdlGetConfigStr("dkim_selector");
+       char *dkim_from_domain = (strchr(fromaddr, '@') ? strchr(fromaddr, '@')+1 : NULL);
+       if (
+               !IsEmptyStr(dkim_from_domain)                   // Is the sending domain non-empty?
+               && IsDirectory(fromaddr, 0)                     // and is it one of "our" domains?
+               && !IsEmptyStr(dkim_private_key)                // Do we have a private signing key?
+               && !IsEmptyStr(dkim_selector)                   // and a selector to go with it?
+       ) {
+               // If you answered "yes" to all of the above questions, congratulations!  We get to sign the message!
+               syslog(LOG_DEBUG, "smtpclient: dkim-signing for selector <%s> in domain <%s>", dkim_selector, dkim_from_domain);
+
+               // Remember, the dkim_sign() function is capable of handling a PEM-encoded PKCS#7 private key that
+               // has had all of its newlines replaced by underscores -- which is exactly how we store it.
+               dkim_sign(s.TheMessage,dkim_private_key, dkim_from_domain, dkim_selector);
+       }
+
+       // Prepare the buffer for transmittal
+       s.bytes_total = StrLength(s.TheMessage);
+       s.bytes_sent = 0;
        response_code = 421;
-                                       // keep trying MXes until one works or we run out
+
+
+       // Keep trying MXes until one works or we run out.
        for (i = 0; ((i < num_mx) && ((response_code / 100) == 4)); ++i) {
                response_code = 421;    // default 421 makes non-protocol errors transient
                s.bytes_sent = 0;       // rewind our buffer in case we try multiple MXes
@@ -323,7 +346,7 @@ void smtp_process_one_msg(long qmsgnum) {
 
        msg = CtdlFetchMessage(qmsgnum, 1);
        if (msg == NULL) {
-               syslog(LOG_WARNING, "smtpclient: %ld does not exist", qmsgnum);
+               syslog(LOG_WARNING, "smtpclient: msg#%ld does not exist", qmsgnum);
                return;
        }
 
@@ -463,7 +486,7 @@ void smtp_process_one_msg(long qmsgnum) {
                }
        }
        else {
-               syslog(LOG_DEBUG, "smtpclient: %ld retry time not reached", qmsgnum);
+               syslog(LOG_DEBUG, "smtpclient: msg#%ld retry time not reached", qmsgnum);
        }
 
        if (bounceto != NULL) {
@@ -577,6 +600,7 @@ char *ctdl_module_init_smtpclient(void) {
                CtdlRegisterSessionHook(smtp_do_queue_quick, EVT_HOUSE, PRIO_AGGR + 51);
                CtdlRegisterSessionHook(smtp_do_queue_full, EVT_TIMER, PRIO_AGGR + 51);
                smtp_init_spoolout();
+               dkim_init();
        }
 
        // return our module id for the log