*
*/
+#ifdef DLL_EXPORT
+#define IN_LIBCIT
+#endif
+
#include "sysdep.h"
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
-#include <time.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
#include <ctype.h>
#include <string.h>
#include <syslog.h>
#include <sys/stat.h>
#include "citadel.h"
#include "server.h"
+#include "dynloader.h"
#include "database.h"
#include "msgbase.h"
#include "support.h"
#include "user_ops.h"
#include "file_ops.h"
#include "control.h"
-#include "dynloader.h"
#include "tools.h"
#include "mime_parser.h"
#include "html.h"
int alias(char *name)
{ /* process alias and routing info for mail */
FILE *fp;
- int a, b;
- char aaa[300], bbb[300];
+ int a, i;
+ char aaa[SIZ], bbb[SIZ];
+ char *ignetcfg = NULL;
+ char *ignetmap = NULL;
+ int at = 0;
+ char node[SIZ];
+ char testnode[SIZ];
+ char buf[SIZ];
remove_any_whitespace_to_the_left_or_right_of_at_symbol(name);
fp = fopen("network/mail.aliases", "r");
- if (fp == NULL)
+ if (fp == NULL) {
fp = fopen("/dev/null", "r");
- if (fp == NULL)
+ }
+ if (fp == NULL) {
return (MES_ERROR);
+ }
strcpy(aaa, "");
strcpy(bbb, "");
while (fgets(aaa, sizeof aaa, fp) != NULL) {
}
/* determine local or remote type, see citadel.h */
- for (a = 0; a < strlen(name); ++a)
- if (name[a] == '!')
- return (MES_INTERNET);
- for (a = 0; a < strlen(name); ++a)
- if (name[a] == '@')
- for (b = a; b < strlen(name); ++b)
- if (name[b] == '.')
- return (MES_INTERNET);
- b = 0;
- for (a = 0; a < strlen(name); ++a)
- if (name[a] == '@')
- ++b;
- if (b > 1) {
- lprintf(7, "Too many @'s in address\n");
- return (MES_ERROR);
+
+ at = haschar(name, '@');
+ if (at == 0) return(MES_LOCAL); /* no @'s - local address */
+ if (at > 1) return(MES_ERROR); /* >1 @'s - invalid address */
+ remove_any_whitespace_to_the_left_or_right_of_at_symbol(name);
+
+ /* figure out the delivery mode */
+
+ extract_token(node, name, 1, '@');
+
+ /* If there are one or more dots in the nodename, we assume that it
+ * is an FQDN and will attempt SMTP delivery to the Internet.
+ */
+ if (haschar(node, '.') > 0) {
+ return(MES_INTERNET);
}
- if (b == 1) {
- for (a = 0; a < strlen(name); ++a)
- if (name[a] == '@')
- strcpy(bbb, &name[a + 1]);
- while (bbb[0] == 32)
- strcpy(bbb, &bbb[1]);
- fp = fopen("network/mail.sysinfo", "r");
- if (fp == NULL)
- return (MES_ERROR);
-GETSN: do {
- a = getstring(fp, aaa);
- } while ((a >= 0) && (strcasecmp(aaa, bbb)));
- a = getstring(fp, aaa);
- if (!strncmp(aaa, "use ", 4)) {
- strcpy(bbb, &aaa[4]);
- fseek(fp, 0L, 0);
- goto GETSN;
+
+ /* Otherwise we look in the IGnet maps for a valid Citadel node.
+ * Try directly-connected nodes first...
+ */
+ ignetcfg = CtdlGetSysConfig(IGNETCFG);
+ for (i=0; i<num_tokens(ignetcfg, '\n'); ++i) {
+ extract_token(buf, ignetcfg, i, '\n');
+ extract_token(testnode, buf, 0, '|');
+ if (!strcasecmp(node, testnode)) {
+ phree(ignetcfg);
+ return(MES_IGNET);
}
- fclose(fp);
- if (!strncmp(aaa, "uum", 3)) {
- strcpy(bbb, name);
- for (a = 0; a < strlen(bbb); ++a) {
- if (bbb[a] == '@')
- bbb[a] = 0;
- if (bbb[a] == ' ')
- bbb[a] = '_';
- }
- while (bbb[strlen(bbb) - 1] == '_')
- bbb[strlen(bbb) - 1] = 0;
- sprintf(name, &aaa[4], bbb);
- lprintf(9, "returning MES_INTERNET\n");
- return (MES_INTERNET);
- }
- if (!strncmp(aaa, "bin", 3)) {
- strcpy(aaa, name);
- strcpy(bbb, name);
- while (aaa[strlen(aaa) - 1] != '@')
- aaa[strlen(aaa) - 1] = 0;
- aaa[strlen(aaa) - 1] = 0;
- while (aaa[strlen(aaa) - 1] == ' ')
- aaa[strlen(aaa) - 1] = 0;
- while (bbb[0] != '@')
- strcpy(bbb, &bbb[1]);
- strcpy(bbb, &bbb[1]);
- while (bbb[0] == ' ')
- strcpy(bbb, &bbb[1]);
- sprintf(name, "%s @%s", aaa, bbb);
- lprintf(9, "returning MES_BINARY\n");
- return (MES_BINARY);
+ }
+ phree(ignetcfg);
+
+ /*
+ * Then try nodes that are two or more hops away.
+ */
+ ignetmap = CtdlGetSysConfig(IGNETMAP);
+ for (i=0; i<num_tokens(ignetmap, '\n'); ++i) {
+ extract_token(buf, ignetmap, i, '\n');
+ extract_token(testnode, buf, 0, '|');
+ if (!strcasecmp(node, testnode)) {
+ phree(ignetmap);
+ return(MES_IGNET);
}
- return (MES_ERROR);
}
- lprintf(9, "returning MES_LOCAL\n");
- return (MES_LOCAL);
+ phree(ignetmap);
+
+ /* If we get to this point it's an invalid node name */
+ return (MES_ERROR);
}
int num_msgs = 0;
int num_processed = 0;
long thismsg;
- struct SuppMsgInfo smi;
+ struct MetaData smi;
struct CtdlMessage *msg;
int is_seen;
long lastold = 0L;
* Now begin the traversal.
*/
if (num_msgs > 0) for (a = 0; a < num_msgs; ++a) {
- GetSuppMsgInfo(&smi, msglist[a]);
+ GetMetaData(&smi, msglist[a]);
/* Filter out messages that are moderated below the level
* currently being viewed at.
*/
- if (smi.smi_mod < moderation_level) {
+ if (smi.meta_mod < moderation_level) {
msglist[a] = 0L;
}
* out all messages which are not of the type requested.
*/
if (content_type != NULL) if (strlen(content_type) > 0) {
- if (strcasecmp(smi.smi_content_type, content_type)) {
+ if (strcasecmp(smi.meta_content_type, content_type)) {
msglist[a] = 0L;
}
}
void *cbuserdata)
{
- cprintf("part=%s|%s|%s|%s|%s|%d\n",
- name, filename, partnum, disp, cbtype, length);
+ cprintf("part=%s|%s|%s|%s|%s|%ld\n",
+ name, filename, partnum, disp, cbtype, (long)length);
}
/*
- * Callback function for mime parser that wants to display text
+ * Pre callback function for multipart/alternative
+ *
+ * NOTE: this differs from the standard behavior for a reason. Normally when
+ * displaying multipart/alternative you want to show the _last_ usable
+ * format in the message. Here we show the _first_ one, because it's
+ * usually text/plain. Since this set of functions is designed for text
+ * output to non-MIME-aware clients, this is the desired behavior.
+ *
+ */
+void fixed_output_pre(char *name, char *filename, char *partnum, char *disp,
+ void *content, char *cbtype, size_t length, char *encoding,
+ void *cbuserdata)
+{
+ lprintf(9, "fixed_output_pre() type=<%s>\n", cbtype);
+ if (!strcasecmp(cbtype, "multipart/alternative")) {
+ ma->is_ma = 1;
+ ma->did_print = 0;
+ return;
+ }
+}
+
+/*
+ * Post callback function for multipart/alternative
+ */
+void fixed_output_post(char *name, char *filename, char *partnum, char *disp,
+ void *content, char *cbtype, size_t length, char *encoding,
+ void *cbuserdata)
+{
+ lprintf(9, "fixed_output_post() type=<%s>\n", cbtype);
+ if (!strcasecmp(cbtype, "multipart/alternative")) {
+ ma->is_ma = 0;
+ ma->did_print = 0;
+ return;
+ }
+}
+
+/*
+ * Inline callback function for mime parser that wants to display text
*/
void fixed_output(char *name, char *filename, char *partnum, char *disp,
void *content, char *cbtype, size_t length, char *encoding,
char *wptr;
size_t wlen;
CIT_UBYTE ch = 0;
-
- if (!strcasecmp(cbtype, "multipart/alternative")) {
- strcpy(ma->prefix, partnum);
- strcat(ma->prefix, ".");
- ma->is_ma = 1;
- ma->did_print = 0;
- return;
- }
-
- if ( (!strncasecmp(partnum, ma->prefix, strlen(ma->prefix)))
- && (ma->is_ma == 1)
- && (ma->did_print == 1) ) {
+
+ lprintf(9, "fixed_output() type=<%s>\n", cbtype);
+
+ /*
+ * If we're in the middle of a multipart/alternative scope and
+ * we've already printed another section, skip this one.
+ */
+ if ( (ma->is_ma == 1) && (ma->did_print == 1) ) {
lprintf(9, "Skipping part %s (%s)\n", partnum, cbtype);
return;
}
-
ma->did_print = 1;
if ( (!strcasecmp(cbtype, "text/plain"))
phree(ptr);
}
else if (strncasecmp(cbtype, "multipart/", 10)) {
- cprintf("Part %s: %s (%s) (%d bytes)\r\n",
- partnum, filename, cbtype, length);
+ cprintf("Part %s: %s (%s) (%ld bytes)\r\n",
+ partnum, filename, cbtype, (long)length);
}
}
CtdlAllocUserData(SYM_MA_INFO, sizeof(struct ma_info));
memset(ma, 0, sizeof(struct ma_info));
mime_parser(mptr, NULL,
- *fixed_output, NULL, NULL,
+ *fixed_output, *fixed_output_pre, *fixed_output_post,
NULL, 0);
}
return;
}
- cprintf("%d %ld\n", BINARY_FOLLOWS, smr.len);
+ cprintf("%d %ld\n", BINARY_FOLLOWS, (long)smr.len);
client_write(smr.ser, smr.len);
phree(smr.ser);
}
ret->len = ret->len +
strlen(msg->cm_fields[(int)forder[i]]) + 2;
- lprintf(9, "calling malloc(%d)\n", ret->len);
+ lprintf(9, "serialize_message() calling malloc(%ld)\n", (long)ret->len);
ret->ser = mallok(ret->len);
if (ret->ser == NULL) {
ret->len = 0;
strcpy(&ret->ser[wlen], msg->cm_fields[(int)forder[i]]);
wlen = wlen + strlen(msg->cm_fields[(int)forder[i]]) + 1;
}
- if (ret->len != wlen) lprintf(3, "ERROR: len=%d wlen=%d\n",
- ret->len, wlen);
+ if (ret->len != wlen) lprintf(3, "ERROR: len=%ld wlen=%ld\n",
+ (long)ret->len, (long)wlen);
return;
}
char *mptr = NULL;
struct usersupp userbuf;
int a;
- struct SuppMsgInfo smi;
+ struct MetaData smi;
FILE *network_fp = NULL;
static int seqnum = 1;
struct CtdlMessage *imsg;
*/
if (msg->cm_fields['T'] == NULL) {
lprintf(9, "Generating timestamp\n");
- sprintf(aaa, "%ld", time(NULL));
+ sprintf(aaa, "%ld", (long)time(NULL));
msg->cm_fields['T'] = strdoop(aaa);
}
if (ReplicationChecks(msg) > 0) return(-1);
/* Network mail - send a copy to the network program. */
- if ((strlen(recipient) > 0) && (mailtype == MES_BINARY)) {
+ if ((strlen(recipient) > 0) && (mailtype == MES_IGNET)) {
lprintf(9, "Sending network spool\n");
sprintf(aaa, "./network/spoolin/netmail.%04lx.%04x.%04x",
(long) getpid(), CC->cs_pid, ++seqnum);
newmsgid = send_message(msg, network_fp);
if (network_fp != NULL) {
fclose(network_fp);
- system("exec nohup ./netproc -i >/dev/null 2>&1 &");
+ /* FIXME start a network run here */
}
if (newmsgid <= 0L) return(-1);
* be a critical section because nobody else knows about this message
* yet.
*/
- lprintf(9, "Creating SuppMsgInfo record\n");
- memset(&smi, 0, sizeof(struct SuppMsgInfo));
- smi.smi_msgnum = newmsgid;
- smi.smi_refcount = 0;
- safestrncpy(smi.smi_content_type, content_type, 64);
- PutSuppMsgInfo(&smi);
+ lprintf(9, "Creating MetaData record\n");
+ memset(&smi, 0, sizeof(struct MetaData));
+ smi.meta_msgnum = newmsgid;
+ smi.meta_refcount = 0;
+ safestrncpy(smi.meta_content_type, content_type, 64);
+ PutMetaData(&smi);
/* Now figure out where to store the pointers */
lprintf(9, "Storing pointers\n");
"Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n"
"bounceto|%s@%s\n"
"remote|%s|0||\n",
- SPOOLMIME, newmsgid, time(NULL),
+ SPOOLMIME, newmsgid, (long)time(NULL),
msg->cm_fields['A'], msg->cm_fields['N'],
recipient );
} else {
buffer_len = (buffer_len * 2);
m = ptr;
- lprintf(9, "buffer_len is %d\n", buffer_len);
+ lprintf(9, "buffer_len is %ld\n", (long)buffer_len);
}
}
* Build a binary message to be saved on disk.
*/
-struct CtdlMessage *make_message(
+static struct CtdlMessage *make_message(
struct usersupp *author, /* author's usersupp structure */
char *recipient, /* NULL if it's not mail */
char *room, /* room where it's going */
/* Don't confuse the poor folks if it's not routed mail. */
strcpy(dest_node, "");
- /* If net_type is MES_BINARY, split out the destination node. */
- if (net_type == MES_BINARY) {
+ /* If net_type is MES_IGNET, split out the destination node. */
+ if (net_type == MES_IGNET) {
strcpy(dest_node, NODENAME);
for (a = 0; a < strlen(recipient); ++a) {
if (recipient[a] == '@') {
sprintf(buf, "cit%ld", author->usernum); /* Path */
msg->cm_fields['P'] = strdoop(buf);
- sprintf(buf, "%ld", time(NULL)); /* timestamp */
+ sprintf(buf, "%ld", (long)time(NULL)); /* timestamp */
msg->cm_fields['T'] = strdoop(buf);
if (fake_name[0]) /* author */
cprintf("%d %ld\n", SEND_BINARY, msglen);
- client_read(&ch, 1); /* 0xFF magic number */
+ client_read((char*)&ch, 1); /* 0xFF magic number */
msg->cm_magic = CTDLMESSAGE_MAGIC;
- client_read(&ch, 1); /* anon type */
+ client_read((char*)&ch, 1); /* anon type */
msg->cm_anon_type = ch;
- client_read(&ch, 1); /* format type */
+ client_read((char*)&ch, 1); /* format type */
msg->cm_format_type = ch;
msglen = msglen - 3;
while (msglen > 0) {
- client_read(&which_field, 1);
+ client_read((char*)&which_field, 1);
if (!isalpha(which_field)) valid_msg = 0;
--msglen;
tempbuf[0] = 0;
do {
- client_read(&ch, 1);
+ client_read((char*)&ch, 1);
--msglen;
a = strlen(tempbuf);
tempbuf[a+1] = 0;
int i;
int num_deleted = 0;
int delete_this;
- struct SuppMsgInfo smi;
+ struct MetaData smi;
lprintf(9, "CtdlDeleteMessages(%s, %ld, %s)\n",
room_name, dmsgnum, content_type);
if (strlen(content_type) == 0) {
delete_this |= 0x02;
} else {
- GetSuppMsgInfo(&smi, msglist[i]);
- if (!strcasecmp(smi.smi_content_type,
+ GetMetaData(&smi, msglist[i]);
+ if (!strcasecmp(smi.meta_content_type,
content_type)) {
delete_this |= 0x02;
}
/*
- * GetSuppMsgInfo() - Get the supplementary record for a message
+ * GetMetaData() - Get the supplementary record for a message
*/
-void GetSuppMsgInfo(struct SuppMsgInfo *smibuf, long msgnum)
+void GetMetaData(struct MetaData *smibuf, long msgnum)
{
struct cdbdata *cdbsmi;
long TheIndex;
- memset(smibuf, 0, sizeof(struct SuppMsgInfo));
- smibuf->smi_msgnum = msgnum;
- smibuf->smi_refcount = 1; /* Default reference count is 1 */
+ memset(smibuf, 0, sizeof(struct MetaData));
+ smibuf->meta_msgnum = msgnum;
+ smibuf->meta_refcount = 1; /* Default reference count is 1 */
/* Use the negative of the message number for its supp record index */
TheIndex = (0L - msgnum);
return; /* record not found; go with defaults */
}
memcpy(smibuf, cdbsmi->ptr,
- ((cdbsmi->len > sizeof(struct SuppMsgInfo)) ?
- sizeof(struct SuppMsgInfo) : cdbsmi->len));
+ ((cdbsmi->len > sizeof(struct MetaData)) ?
+ sizeof(struct MetaData) : cdbsmi->len));
cdb_free(cdbsmi);
return;
}
/*
- * PutSuppMsgInfo() - (re)write supplementary record for a message
+ * PutMetaData() - (re)write supplementary record for a message
*/
-void PutSuppMsgInfo(struct SuppMsgInfo *smibuf)
+void PutMetaData(struct MetaData *smibuf)
{
long TheIndex;
/* Use the negative of the message number for its supp record index */
- TheIndex = (0L - smibuf->smi_msgnum);
+ TheIndex = (0L - smibuf->meta_msgnum);
- lprintf(9, "PuttSuppMsgInfo(%ld) - ref count is %d\n",
- smibuf->smi_msgnum, smibuf->smi_refcount);
+ lprintf(9, "PuttMetaData(%ld) - ref count is %d\n",
+ smibuf->meta_msgnum, smibuf->meta_refcount);
cdb_store(CDB_MSGMAIN,
&TheIndex, sizeof(long),
- smibuf, sizeof(struct SuppMsgInfo));
+ smibuf, sizeof(struct MetaData));
}
void AdjRefCount(long msgnum, int incr)
{
- struct SuppMsgInfo smi;
+ struct MetaData smi;
long delnum;
/* This is a *tight* critical section; please keep it that way, as
* Complicating this any further will surely cause deadlock!
*/
begin_critical_section(S_SUPPMSGMAIN);
- GetSuppMsgInfo(&smi, msgnum);
+ GetMetaData(&smi, msgnum);
lprintf(9, "Ref count for message <%ld> before write is <%d>\n",
- msgnum, smi.smi_refcount);
- smi.smi_refcount += incr;
- PutSuppMsgInfo(&smi);
+ msgnum, smi.meta_refcount);
+ smi.meta_refcount += incr;
+ PutMetaData(&smi);
end_critical_section(S_SUPPMSGMAIN);
lprintf(9, "Ref count for message <%ld> after write is <%d>\n",
- msgnum, smi.smi_refcount);
+ msgnum, smi.meta_refcount);
/* If the reference count is now zero, delete the message
* (and its supplementary record as well).
*/
- if (smi.smi_refcount == 0) {
+ if (smi.meta_refcount == 0) {
lprintf(9, "Deleting message <%ld>\n", msgnum);
delnum = msgnum;
cdb_delete(CDB_MSGMAIN, &delnum, sizeof(long));
getroom(&CC->quickroom, hold_rm);
- lprintf(9, "eggstracting...\n");
if (conf != NULL) do {
extract_token(buf, conf, 0, '\n');
- lprintf(9, "eggstracted <%s>\n", buf);
strcpy(conf, &conf[strlen(buf)+1]);
} while ( (strlen(conf)>0) && (strlen(buf)>0) );