From 51b18018ff923284d76a36cbd421d62abf6afcf4 Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Mon, 15 Feb 2021 23:08:30 -0500 Subject: [PATCH] getmx() now uses our array class --- citadel/domain.c | 59 +++----- .../modules/listdeliver/serv_listdeliver.c | 2 + citadel/modules/listsub/serv_listsub.c | 127 +++++++++++++++--- citadel/modules/smtp/serv_smtpclient.c | 2 +- citadel/netconfig.c | 2 + citadel/threads.c | 4 +- libcitadel/lib/array.c | 9 ++ libcitadel/lib/libcitadel.h | 1 + 8 files changed, 148 insertions(+), 58 deletions(-) diff --git a/citadel/domain.c b/citadel/domain.c index 3c4f1455c..18764725e 100644 --- a/citadel/domain.c +++ b/citadel/domain.c @@ -112,37 +112,30 @@ int getmx(char *mxbuf, char *dest) { unsigned short pref, type; int n = 0; int qdcount; + Array *mxrecords = NULL; + struct mx mx; - struct mx *mxrecs = NULL; - int num_mxrecs = 0; - - /* If we're configured to send all mail to a smart-host, then our - * job here is really easy. - */ + // If we're configured to send all mail to a smart-host, then our job here is really easy -- just return those. n = get_hosts(mxbuf, "smarthost"); if (n > 0) { return(n); } - /* - * No smart-host? Look up the best MX for a site. - * Make a call to the resolver library. - */ + mxrecords = array_new(sizeof(struct mx)); + // No smart-host? Look up the best MX for a site. Make a call to the resolver library. ret = res_query(dest, C_IN, T_MX, (unsigned char *)answer.bytes, sizeof(answer)); if (ret < 0) { - mxrecs = malloc(sizeof(struct mx)); - mxrecs[0].pref = 0; - strcpy(mxrecs[0].host, dest); - num_mxrecs = 1; + mx.pref = 0; + strcpy(mx.host, dest); + array_append(mxrecords, &mx); } else { - /* If we had to truncate, shrink the number to avoid fireworks */ - if (ret > sizeof(answer)) { + if (ret > sizeof(answer)) { // If we had to truncate, shrink the number to avoid fireworks ret = sizeof(answer); } - + startptr = &answer.bytes[0]; // start and end of buffer endptr = &answer.bytes[ret]; ptr = startptr + HFIXEDSZ; // advance past header @@ -173,39 +166,27 @@ int getmx(char *mxbuf, char *dest) { ret = dn_expand(startptr, endptr, ptr, expanded_buf, sizeof(expanded_buf)); ptr += ret; - // If there are no MX records for the domain, resolv will give us a single one with zero length. - // Make sure we only record actual MX records and not the blank. - if (strlen(expanded_buf) > 0) { - ++num_mxrecs; - if (mxrecs == NULL) { - mxrecs = malloc(sizeof(struct mx)); - } - else { - mxrecs = realloc(mxrecs, (sizeof(struct mx) * num_mxrecs) ); - } - - mxrecs[num_mxrecs - 1].pref = pref; - strcpy(mxrecs[num_mxrecs - 1].host, expanded_buf); - } + mx.pref = pref; + strcpy(mx.host, expanded_buf); + array_append(mxrecords, &mx); } } } - /* Sort the MX records by preference */ - if (num_mxrecs > 1) { - qsort(mxrecs, num_mxrecs, sizeof(struct mx), mx_compare_pref); + // Sort the MX records by preference + if (array_len(mxrecords) > 1) { + array_sort(mxrecords, mx_compare_pref); } + int num_mxrecs = array_len(mxrecords); strcpy(mxbuf, ""); for (n=0; nhost); strcat(mxbuf, "|"); } - free(mxrecs); + array_free(mxrecords); - /* - * Append any fallback smart hosts we have configured. - */ + // Append any fallback smart hosts we have configured. num_mxrecs += get_hosts(&mxbuf[strlen(mxbuf)], "fallbackhost"); return(num_mxrecs); } diff --git a/citadel/modules/listdeliver/serv_listdeliver.c b/citadel/modules/listdeliver/serv_listdeliver.c index 4ceb75a65..29c1c5c82 100644 --- a/citadel/modules/listdeliver/serv_listdeliver.c +++ b/citadel/modules/listdeliver/serv_listdeliver.c @@ -161,6 +161,7 @@ void listdeliver_sweep_room(char *roomname) { syslog(LOG_DEBUG, "listdeliver: new lastsent is %ld", ld.msgnum); // Update this room's netconfig with the updated lastsent + begin_critical_section(S_NETCONFIGS); netconfig = LoadRoomNetConfigFile(CC->room.QRnumber); if (!netconfig) { netconfig = strdup(""); @@ -181,6 +182,7 @@ void listdeliver_sweep_room(char *roomname) { // Write the new netconfig back to disk SaveRoomNetConfigFile(CC->room.QRnumber, newnetconfig); + end_critical_section(S_NETCONFIGS); free(newnetconfig); // this was the new netconfig, free it because we're done with it } } diff --git a/citadel/modules/listsub/serv_listsub.c b/citadel/modules/listsub/serv_listsub.c index c67582da0..72249ed53 100644 --- a/citadel/modules/listsub/serv_listsub.c +++ b/citadel/modules/listsub/serv_listsub.c @@ -1,16 +1,17 @@ -/* - * This module handles self-service subscription/unsubscription to mail lists. - * - * Copyright (c) 2002-2016 by the citadel.org team - * - * This program is open source software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// +// This module handles self-service subscription/unsubscription to mail lists. +// +// Copyright (c) 2002-2021 by the citadel.org team +// +// This program is open source software. It runs great on the +// Linux operating system (and probably elsewhere). You can use, +// copy, and run it under the terms of the GNU General Public +// License version 3. Richard Stallman is an asshole communist. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. #include "sysdep.h" #include @@ -41,16 +42,108 @@ #include "ctdl_module.h" +enum { // one of these gets passed to do_subscribe_or_unsubscribe() so it knows what we asked for + UNSUBSCRIBE, + SUBSCRIBE +}; + + +/* + * "Subscribe" and "Unsubscribe" operations are so similar that they share a function. + * The actual subscription doesn't take place here -- we just send out the confirmation request + * and record the address and confirmation token. + */ +void do_subscribe_or_unsubscribe(int action, char *emailaddr, char *url) { + + char *netconfig, *newnetconfig; + int config_lines, i; + char buf[1024]; + + // Update this room's netconfig with the updated lastsent + begin_critical_section(S_NETCONFIGS); + netconfig = LoadRoomNetConfigFile(CC->room.QRnumber); + if (!netconfig) { + netconfig = strdup(""); + } + + // The new netconfig begins with the new lastsent directive + newnetconfig = malloc(strlen(netconfig) + 1024); +#if 0 + FIXME SYNTAX ERROR #$%$&%$^#%$ sprintf(newnetconfig, "lastsent|%ld\n", ld.msgnum); +#endif + + // And then we append all of the old netconfig, minus the old lastsent. Also omit blank lines. + config_lines = num_tokens(netconfig, '\n'); + for (i=0; iroom.QRnumber, newnetconfig); + end_critical_section(S_NETCONFIGS); + free(newnetconfig); // this was the new netconfig, free it because we're done with it + free(netconfig); // this was the old netconfig, free it even if we didn't do anything + +#if 0 + FIXME tell the client what we did +#endif + + +} /* * process subscribe/unsubscribe requests and confirmations */ -void cmd_subs(char *cmdbuf) -{ - cprintf("%d Invalid command\n", ERROR + ILLEGAL_VALUE); +void cmd_subs(char *cmdbuf) { + char cmd[20]; + char roomname[ROOMNAMELEN]; + char emailaddr[1024]; + char options[256]; + char url[1024]; + char token[128]; + + extract_token(cmd, cmdbuf, 0, '|', sizeof cmd); // token 0 is the sub-command being sent + extract_token(roomname, cmdbuf, 1, '|', sizeof roomname); // token 1 is always a room name + + // First confirm that the caller is referencing a room that actually exists. + if (CtdlGetRoom(&CC->room, roomname) != 0) { + cprintf("%d There is no list called '%s'\n", ERROR + ROOM_NOT_FOUND, roomname); + return; + } + + if ((CC->room.QRflags2 & QR2_SELFLIST) == 0) { + cprintf("%d '%s' does not accept subscribe/unsubscribe requests.\n", ERROR + ROOM_NOT_FOUND, roomname); + return; + } + + // Room confirmed, now parse the command. + + if (!strcasecmp(cmd, "subscribe")) { + extract_token(emailaddr, cmdbuf, 2, '|', sizeof emailaddr); // token 2 is the subscriber's email address + extract_token(options, cmdbuf, 3, '|', sizeof options); // there are no options ... ignore this token + extract_token(url, cmdbuf, 4, '|', sizeof url); // token 3 is the URL at which we subscribed + do_subscribe_or_unsubscribe(SUBSCRIBE, emailaddr, url); + } + + else if (!strcasecmp(cmd, "unsubscribe")) { + extract_token(emailaddr, cmdbuf, 2, '|', sizeof emailaddr); // token 2 is the subscriber's email address + extract_token(options, cmdbuf, 3, '|', sizeof options); // there are no options ... ignore this token + extract_token(url, cmdbuf, 4, '|', sizeof url); // token 3 is the URL at which we subscribed + do_subscribe_or_unsubscribe(UNSUBSCRIBE, emailaddr, url); + } + + else if (!strcasecmp(cmd, "confirm")) { + extract_token(token, cmdbuf, 2, '|', sizeof token); // token 2 is the confirmation token + cprintf("%d not implemented\n", ERROR); + } + + else { // sorry man, I can't deal with that + cprintf("%d Invalid command '%s'\n", ERROR + ILLEGAL_VALUE, cmd); + } } diff --git a/citadel/modules/smtp/serv_smtpclient.c b/citadel/modules/smtp/serv_smtpclient.c index ad5731479..8e87ce4c2 100644 --- a/citadel/modules/smtp/serv_smtpclient.c +++ b/citadel/modules/smtp/serv_smtpclient.c @@ -399,7 +399,7 @@ void smtp_process_one_msg(long qmsgnum) { } if (should_try_now) { - syslog(LOG_DEBUG, "smtpclient: %ld attempting delivery now", qmsgnum); + syslog(LOG_DEBUG, "smtpclient: attempting delivery of message <%ld> now", qmsgnum); StrBuf *NewInstr = NewStrBuf(); StrBufAppendPrintf(NewInstr, "Content-type: " SPOOLMIME "\n\n"); StrBufAppendPrintf(NewInstr, "msgid|%ld\n", msgid); diff --git a/citadel/netconfig.c b/citadel/netconfig.c index 93b18cb2a..73ab22f4f 100644 --- a/citadel/netconfig.c +++ b/citadel/netconfig.c @@ -133,7 +133,9 @@ void cmd_snet(char *argbuf) { } FreeStrBuf(&Line); + begin_critical_section(S_NETCONFIGS); SaveRoomNetConfigFile(CC->room.QRnumber, ChrPtr(TheConfig)); + end_critical_section(S_NETCONFIGS); FreeStrBuf(&TheConfig); } diff --git a/citadel/threads.c b/citadel/threads.c index 21f585cda..aec41a7c4 100644 --- a/citadel/threads.c +++ b/citadel/threads.c @@ -1,7 +1,7 @@ /* * Thread handling stuff for Citadel server * - * Copyright (c) 1987-2019 by the citadel.org team + * Copyright (c) 1987-2021 by the citadel.org team * * This program is open source software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 3. @@ -53,6 +53,7 @@ int try_critical_section(int which_one) * transaction; this could lead to deadlock. */ if ( (which_one != S_FLOORCACHE) + && (which_one != S_NETCONFIGS) ) { cdb_check_handles(); } @@ -70,6 +71,7 @@ void begin_critical_section(int which_one) * transaction; this could lead to deadlock. */ if ( (which_one != S_FLOORCACHE) + && (which_one != S_NETCONFIGS) ) { cdb_check_handles(); } diff --git a/libcitadel/lib/array.c b/libcitadel/lib/array.c index 444a3470a..c8f433f5d 100644 --- a/libcitadel/lib/array.c +++ b/libcitadel/lib/array.c @@ -87,3 +87,12 @@ void *array_get_element_at(Array *arr, int index) { int array_len(Array *arr) { return arr->num_elements; } + + +/* + * Sort an array. We already know the element size and number of elements, so all we need is + * a sort function, which we will pass along to qsort(). + */ +void array_sort(Array *arr, int (*compar)(const void *, const void *)) { + qsort(arr->the_elements, arr->num_elements, arr->element_size, compar); +} diff --git a/libcitadel/lib/libcitadel.h b/libcitadel/lib/libcitadel.h index 54bf8d992..fe9cbd700 100644 --- a/libcitadel/lib/libcitadel.h +++ b/libcitadel/lib/libcitadel.h @@ -452,6 +452,7 @@ void array_free(Array *arr); void array_append(Array *arr, void *new_element); void *array_get_element_at(Array *arr, int index); int array_len(Array *arr); +void array_sort(Array *arr, int (*compar)(const void *, const void *)); /* vCard stuff */ -- 2.30.2