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
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; n<num_mxrecs; ++n) {
- strcat(mxbuf, mxrecs[n].host);
+ strcat(mxbuf, ((struct mx *)array_get_element_at(mxrecords, n))->host);
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);
}
-/*
- * 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 <stdlib.h>
#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; i<config_lines; ++i) {
+ extract_token(buf, netconfig, i, '\n', sizeof buf);
+ if ( (!IsEmptyStr(buf)) && (strncasecmp(buf, "lastsent|", 9)) ) {
+ sprintf(&newnetconfig[strlen(newnetconfig)], "%s\n", buf);
+ }
+ }
-// FIXME rewrite the subscribe-o-matic AJC 2021
+ // 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
+ 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);
+ }
}