-/* $Id$ */
+/*
+ * $Id$
+ *
+ * Implements the message store.
+ *
+ */
+
+#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 <limits.h>
-#include "citadel.h"
-#include "server.h"
#include <errno.h>
+#include <stdarg.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"
+#include "genstamp.h"
+#include "internet_addressing.h"
#define desired_section ((char *)CtdlGetUserData(SYM_DESIRED_SECTION))
#define ma ((struct ma_info *)CtdlGetUserData(SYM_MA_INFO))
"from",
"", "", "",
"exti",
- "", "",
+ "rfca",
+ "",
"hnod",
"msgn",
"", "", "",
{
int i;
- for (i = 0; i < strlen(name); ++i)
+ for (i = 0; i < strlen(name); ++i) {
if (name[i] == '@') {
- if (i > 0)
- if (isspace(name[i - 1])) {
- strcpy(&name[i - 1], &name[i]);
- i = 0;
- }
+ while (isspace(name[i - 1]) && i > 0) {
+ strcpy(&name[i - 1], &name[i]);
+ --i;
+ }
while (isspace(name[i + 1])) {
strcpy(&name[i + 1], &name[i + 2]);
}
}
+ }
}
fclose(fp);
lprintf(7, "Mail is being forwarded to %s\n", name);
+ /* Change "user @ xxx" to "user" if xxx is an alias for this host */
+ for (a=0; a<strlen(name); ++a) {
+ if (name[a] == '@') {
+ if (CtdlHostAlias(&name[a+1]) == hostalias_localhost) {
+ name[a] = 0;
+ lprintf(7, "Changed to <%s>\n", name);
+ }
+ }
+ }
+
/* determine local or remote type, see citadel.h */
for (a = 0; a < strlen(name); ++a)
if (name[a] == '!')
strcpy(bbb, &bbb[1]);
fp = fopen("network/mail.sysinfo", "r");
if (fp == NULL)
- return (MES_ERROR);
- GETSN:do {
+ return (MES_ERROR);
+GETSN: do {
a = getstring(fp, aaa);
} while ((a >= 0) && (strcasecmp(aaa, bbb)));
a = getstring(fp, aaa);
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)) {
while (bbb[0] == ' ')
strcpy(bbb, &bbb[1]);
sprintf(name, "%s @%s", aaa, bbb);
+ lprintf(9, "returning MES_BINARY\n");
return (MES_BINARY);
}
return (MES_ERROR);
}
+ lprintf(9, "returning MES_LOCAL\n");
return (MES_LOCAL);
}
-void simple_listing(long msgnum)
+void simple_listing(long msgnum, void *userdata)
{
cprintf("%ld\n", msgnum);
}
}
+/*
+ * Manipulate the "seen msgs" string.
+ */
+void CtdlSetSeen(long target_msgnum, int target_setting) {
+ char newseen[SIZ];
+ struct cdbdata *cdbfr;
+ int i;
+ int is_seen = 0;
+ int was_seen = 1;
+ long lo = (-1L);
+ long hi = (-1L);
+ struct visit vbuf;
+ long *msglist;
+ int num_msgs = 0;
+
+ /* Learn about the user and room in question */
+ get_mm();
+ getuser(&CC->usersupp, CC->curr_user);
+ CtdlGetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
+
+ /* Load the message list */
+ cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->quickroom.QRnumber, sizeof(long));
+ if (cdbfr != NULL) {
+ msglist = mallok(cdbfr->len);
+ memcpy(msglist, cdbfr->ptr, cdbfr->len);
+ num_msgs = cdbfr->len / sizeof(long);
+ cdb_free(cdbfr);
+ } else {
+ return; /* No messages at all? No further action. */
+ }
+
+ lprintf(9, "before optimize: %s\n", vbuf.v_seen);
+ strcpy(newseen, "");
+
+ for (i=0; i<num_msgs; ++i) {
+ is_seen = 0;
+
+ if (msglist[i] == target_msgnum) {
+ is_seen = target_setting;
+ }
+ else {
+ if (is_msg_in_mset(vbuf.v_seen, msglist[i])) {
+ is_seen = 1;
+ }
+ }
+
+ if (is_seen == 1) {
+ if (lo < 0L) lo = msglist[i];
+ hi = msglist[i];
+ }
+ if ( ((is_seen == 0) && (was_seen == 1))
+ || ((is_seen == 1) && (i == num_msgs-1)) ) {
+ if ( (strlen(newseen) + 20) > SIZ) {
+ strcpy(newseen, &newseen[20]);
+ newseen[0] = '*';
+ }
+ if (strlen(newseen) > 0) strcat(newseen, ",");
+ if (lo == hi) {
+ sprintf(&newseen[strlen(newseen)], "%ld", lo);
+ }
+ else {
+ sprintf(&newseen[strlen(newseen)], "%ld:%ld",
+ lo, hi);
+ }
+ lo = (-1L);
+ hi = (-1L);
+ }
+ was_seen = is_seen;
+ }
+
+ safestrncpy(vbuf.v_seen, newseen, SIZ);
+ lprintf(9, " after optimize: %s\n", vbuf.v_seen);
+ phree(msglist);
+ CtdlSetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
+}
/*
* API function to perform an operation for each qualifying message in the
- * current room.
+ * current room. (Returns the number of messages processed.)
*/
-void CtdlForEachMessage(int mode, long ref,
+int CtdlForEachMessage(int mode, long ref,
+ int moderation_level,
char *content_type,
struct CtdlMessage *compare,
- void (*CallBack) (long msgnum))
+ void (*CallBack) (long, void *),
+ void *userdata)
{
int a;
struct cdbdata *cdbfr;
long *msglist = NULL;
int num_msgs = 0;
+ int num_processed = 0;
long thismsg;
struct SuppMsgInfo smi;
struct CtdlMessage *msg;
+ int is_seen;
+ long lastold = 0L;
+ int printed_lastold = 0;
/* Learn about the user and room in question */
get_mm();
num_msgs = cdbfr->len / sizeof(long);
cdb_free(cdbfr);
} else {
- return; /* No messages at all? No further action. */
+ return 0; /* No messages at all? No further action. */
}
- /* If the caller is looking for a specific MIME type, then filter
- * out all messages which are not of the type requested.
+ /*
+ * Now begin the traversal.
*/
- if (num_msgs > 0)
- if (content_type != NULL)
- if (strlen(content_type) > 0)
- for (a = 0; a < num_msgs; ++a) {
- GetSuppMsgInfo(&smi, msglist[a]);
- if (strcasecmp(smi.smi_content_type, content_type)) {
- msglist[a] = 0L;
- }
- }
+ if (num_msgs > 0) for (a = 0; a < num_msgs; ++a) {
+ GetSuppMsgInfo(&smi, msglist[a]);
+
+ /* Filter out messages that are moderated below the level
+ * currently being viewed at.
+ */
+ if (smi.smi_mod < moderation_level) {
+ msglist[a] = 0L;
+ }
+
+ /* If the caller is looking for a specific MIME type, filter
+ * 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)) {
+ msglist[a] = 0L;
+ }
+ }
+ }
num_msgs = sort_msglist(msglist, num_msgs);
if (num_msgs > 0)
for (a = 0; a < num_msgs; ++a) {
thismsg = msglist[a];
- if ((thismsg > 0)
+ is_seen = is_msg_in_mset(vbuf.v_seen, thismsg);
+ if (is_seen) lastold = thismsg;
+ if ((thismsg > 0L)
&& (
(mode == MSGS_ALL)
- || ((mode == MSGS_OLD) && (thismsg <= vbuf.v_lastseen))
- || ((mode == MSGS_NEW) && (thismsg > vbuf.v_lastseen))
- || ((mode == MSGS_NEW) && (thismsg >= vbuf.v_lastseen)
- && (CC->usersupp.flags & US_LASTOLD))
+ || ((mode == MSGS_OLD) && (is_seen))
+ || ((mode == MSGS_NEW) && (!is_seen))
|| ((mode == MSGS_LAST) && (a >= (num_msgs - ref)))
|| ((mode == MSGS_FIRST) && (a < ref))
|| ((mode == MSGS_GT) && (thismsg > ref))
+ || ((mode == MSGS_EQ) && (thismsg == ref))
)
) {
- CallBack(thismsg);
+ if ((mode == MSGS_NEW) && (CC->usersupp.flags & US_LASTOLD) && (lastold > 0L) && (printed_lastold == 0) && (!is_seen)) {
+ if (CallBack)
+ CallBack(lastold, userdata);
+ printed_lastold = 1;
+ ++num_processed;
+ }
+ if (CallBack) CallBack(thismsg, userdata);
+ ++num_processed;
}
}
phree(msglist); /* Clean up */
+ return num_processed;
}
void cmd_msgs(char *cmdbuf)
{
int mode = 0;
- char which[256];
- char buf[256];
- char tfield[256];
- char tvalue[256];
+ char which[SIZ];
+ char buf[SIZ];
+ char tfield[SIZ];
+ char tvalue[SIZ];
int cm_ref = 0;
int i;
int with_template = 0;
cprintf("%d Message list...\n", LISTING_FOLLOWS);
}
- CtdlForEachMessage(mode, cm_ref, NULL, template, simple_listing);
+ CtdlForEachMessage(mode, cm_ref,
+ CC->usersupp.moderation_filter,
+ NULL, template, simple_listing, NULL);
if (template != NULL) CtdlFreeMessage(template);
cprintf("000\n");
}
*/
void help_subst(char *strbuf, char *source, char *dest)
{
- char workbuf[256];
+ char workbuf[SIZ];
int p;
while (p = pattern2(strbuf, source), (p >= 0)) {
* for here is to format text out to 80 columns before sending it
* to the client. The client software may reformat it again.
*/
-void memfmout(int width, char *mptr, char subst)
- /* screen width to use */
- /* where are we going to get our text from? */
- /* nonzero if we should use hypertext mode */
+void memfmout(
+ int width, /* screen width to use */
+ char *mptr, /* where are we going to get our text from? */
+ char subst, /* nonzero if we should do substitutions */
+ char *nl) /* string to terminate lines with */
{
int a, b, c;
int real = 0;
int old = 0;
CIT_UBYTE ch;
char aaa[140];
- char buffer[256];
+ char buffer[SIZ];
strcpy(aaa, "");
old = 255;
strcpy(buffer, "");
c = 1; /* c is the current pos */
-FMTA: if (subst) {
- while (ch = *mptr, ((ch != 0) && (strlen(buffer) < 126))) {
- ch = *mptr++;
- buffer[strlen(buffer) + 1] = 0;
- buffer[strlen(buffer)] = ch;
- }
-
- if (buffer[0] == '^')
- do_help_subst(buffer);
+ do {
+ if (subst) {
+ while (ch = *mptr, ((ch != 0) && (strlen(buffer) < 126))) {
+ ch = *mptr++;
+ buffer[strlen(buffer) + 1] = 0;
+ buffer[strlen(buffer)] = ch;
+ }
- buffer[strlen(buffer) + 1] = 0;
- a = buffer[0];
- strcpy(buffer, &buffer[1]);
- } else {
- ch = *mptr++;
- }
+ if (buffer[0] == '^')
+ do_help_subst(buffer);
- old = real;
- real = ch;
- if (ch <= 0)
- goto FMTEND;
+ buffer[strlen(buffer) + 1] = 0;
+ a = buffer[0];
+ strcpy(buffer, &buffer[1]);
+ } else {
+ ch = *mptr++;
+ }
- if (((ch == 13) || (ch == 10)) && (old != 13) && (old != 10))
- ch = 32;
- if (((old == 13) || (old == 10)) && (isspace(real))) {
- cprintf("\n");
- c = 1;
- }
- if (ch > 126)
- goto FMTA;
+ old = real;
+ real = ch;
- if (ch > 32) {
- if (((strlen(aaa) + c) > (width - 5)) && (strlen(aaa) > (width - 5))) {
- cprintf("\n%s", aaa);
- c = strlen(aaa);
- aaa[0] = 0;
+ if (((ch == 13) || (ch == 10)) && (old != 13) && (old != 10))
+ ch = 32;
+ if (((old == 13) || (old == 10)) && (isspace(real))) {
+ cprintf("%s", nl);
+ c = 1;
}
- b = strlen(aaa);
- aaa[b] = ch;
- aaa[b + 1] = 0;
- }
- if (ch == 32) {
- if ((strlen(aaa) + c) > (width - 5)) {
- cprintf("\n");
+ if (ch > 126)
+ continue;
+
+ if (ch > 32) {
+ if (((strlen(aaa) + c) > (width - 5)) && (strlen(aaa) > (width - 5))) {
+ cprintf("%s%s", nl, aaa);
+ c = strlen(aaa);
+ aaa[0] = 0;
+ }
+ b = strlen(aaa);
+ aaa[b] = ch;
+ aaa[b + 1] = 0;
+ }
+ if (ch == 32) {
+ if ((strlen(aaa) + c) > (width - 5)) {
+ cprintf("%s", nl);
+ c = 1;
+ }
+ cprintf("%s ", aaa);
+ ++c;
+ c = c + strlen(aaa);
+ strcpy(aaa, "");
+ }
+ if ((ch == 13) || (ch == 10)) {
+ cprintf("%s%s", aaa, nl);
c = 1;
+ strcpy(aaa, "");
}
- cprintf("%s ", aaa);
- ++c;
- c = c + strlen(aaa);
- strcpy(aaa, "");
- goto FMTA;
- }
- if ((ch == 13) || (ch == 10)) {
- cprintf("%s\n", aaa);
- c = 1;
- strcpy(aaa, "");
- goto FMTA;
- }
- goto FMTA;
-FMTEND: cprintf("%s\n", aaa);
+ } while (ch > 0);
+
+ cprintf("%s%s", aaa, nl);
}
* Callback function for mime parser that simply lists the part
*/
void list_this_part(char *name, char *filename, char *partnum, char *disp,
- void *content, char *cbtype, size_t length)
+ void *content, char *cbtype, size_t length, char *encoding,
+ void *cbuserdata)
{
cprintf("part=%s|%s|%s|%s|%s|%d\n",
}
-/*
- * 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 *ptr;
-
- 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, "Skipping part %s (%s)\n", partnum, cbtype);
- return;
- }
-
- ma->did_print = 1;
-
- if (!strcasecmp(cbtype, "text/plain")) {
- client_write(content, length);
- }
- else if (!strcasecmp(cbtype, "text/html")) {
- ptr = html_to_ascii(content, 80, 0);
- client_write(ptr, strlen(ptr));
- phree(ptr);
- }
- else if (strncasecmp(cbtype, "multipart/", 10)) {
- cprintf("Part %s: %s (%s) (%d bytes)\n",
- partnum, filename, cbtype, length);
- }
-}
-
-
/*
* Callback function for mime parser that opens a section for downloading
*/
void mime_download(char *name, char *filename, char *partnum, char *disp,
- void *content, char *cbtype, size_t length)
+ void *content, char *cbtype, size_t length, char *encoding,
+ void *cbuserdata)
{
/* Silently go away if there's already a download open... */
/*
* Load a message from disk into memory.
- * This is used by output_message() and other fetch functions.
+ * This is used by CtdlOutputMsg() and other fetch functions.
*
* NOTE: Caller is responsible for freeing the returned CtdlMessage struct
* using the CtdlMessageFree() function.
if (is_valid_message(msg) == 0) return;
for (i = 0; i < 256; ++i)
- if (msg->cm_fields[i] != NULL)
+ if (msg->cm_fields[i] != NULL) {
phree(msg->cm_fields[i]);
+ }
msg->cm_magic = 0; /* just in case */
phree(msg);
}
-
/*
- * Get a message off disk. (return value is the message's timestamp)
- *
+ * Callback function for mime parser that wants to display text
*/
-void output_message(char *msgid, int mode, int headers_only)
-{
- long msg_num;
- int a, i, k;
- char buf[1024];
- time_t xtime;
- CIT_UBYTE ch;
- char allkeys[256];
- char display_name[256];
+void fixed_output(char *name, char *filename, char *partnum, char *disp,
+ void *content, char *cbtype, size_t length, char *encoding,
+ void *cbuserdata)
+ {
+ char *ptr;
+ 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, "Skipping part %s (%s)\n", partnum, cbtype);
+ return;
+ }
+
+ ma->did_print = 1;
+
+ if ( (!strcasecmp(cbtype, "text/plain"))
+ || (strlen(cbtype)==0) ) {
+ wlen = length;
+ wptr = content;
+ while (wlen--) {
+ ch = *wptr++;
+ /**********
+ if (ch==10) cprintf("\r\n");
+ else cprintf("%c", ch);
+ **********/
+ cprintf("%c", ch);
+ }
+ if (ch != '\n') cprintf("\n");
+ }
+ else if (!strcasecmp(cbtype, "text/html")) {
+ ptr = html_to_ascii(content, 80, 0);
+ wlen = strlen(ptr);
+ wptr = ptr;
+ while (wlen--) {
+ ch = *wptr++;
+ if (ch==10) cprintf("\r\n");
+ else cprintf("%c", ch);
+ }
+ phree(ptr);
+ }
+ else if (strncasecmp(cbtype, "multipart/", 10)) {
+ cprintf("Part %s: %s (%s) (%d bytes)\r\n",
+ partnum, filename, cbtype, length);
+ }
+ }
- struct CtdlMessage *TheMessage = NULL;
- char *mptr;
+/*
+ * Get a message off disk. (returns om_* values found in msgbase.h)
+ *
+ */
+int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */
+ int mode, /* how would you like that message? */
+ int headers_only, /* eschew the message body? */
+ int do_proto, /* do Citadel protocol responses? */
+ int crlf /* Use CRLF newlines instead of LF? */
+) {
+ struct CtdlMessage *TheMessage;
+ int retcode;
- /* buffers needed for RFC822 translation */
- char suser[256];
- char luser[256];
- char snode[256];
- char lnode[256];
- char mid[256];
- /* */
+ lprintf(7, "CtdlOutputMsg() msgnum=%ld, mode=%d\n",
+ msg_num, mode);
- msg_num = atol(msgid);
- safestrncpy(mid, msgid, sizeof mid);
+ TheMessage = NULL;
if ((!(CC->logged_in)) && (!(CC->internal_pgm))) {
- cprintf("%d Not logged in.\n", ERROR + NOT_LOGGED_IN);
- return;
+ if (do_proto) cprintf("%d Not logged in.\n",
+ ERROR + NOT_LOGGED_IN);
+ return(om_not_logged_in);
}
- /* FIX ... small security issue
+ /* FIXME ... small security issue
* We need to check to make sure the requested message is actually
* in the current room, and set msg_ok to 1 only if it is. This
* functionality is currently missing because I'm in a hurry to replace
* broken production code with nonbroken pre-beta code. :( -- ajc
*
if (!msg_ok) {
- cprintf("%d Message %ld is not in this room.\n",
+ if (do_proto) cprintf("%d Message %ld is not in this room.\n",
ERROR, msg_num);
- return;
+ return(om_no_such_msg);
}
*/
*/
TheMessage = CtdlFetchMessage(msg_num);
if (TheMessage == NULL) {
- cprintf("%d Can't locate msg %ld on disk\n", ERROR, msg_num);
- return;
+ if (do_proto) cprintf("%d Can't locate msg %ld on disk\n",
+ ERROR, msg_num);
+ return(om_no_such_msg);
+ }
+
+ retcode = CtdlOutputPreLoadedMsg(
+ TheMessage, msg_num, mode,
+ headers_only, do_proto, crlf);
+
+ CtdlFreeMessage(TheMessage);
+ return(retcode);
+}
+
+
+/*
+ * Get a message off disk. (returns om_* values found in msgbase.h)
+ *
+ */
+int CtdlOutputPreLoadedMsg(struct CtdlMessage *TheMessage,
+ long msg_num,
+ int mode, /* how would you like that message? */
+ int headers_only, /* eschew the message body? */
+ int do_proto, /* do Citadel protocol responses? */
+ int crlf /* Use CRLF newlines instead of LF? */
+) {
+ int i, k;
+ char buf[1024];
+ CIT_UBYTE ch;
+ char allkeys[SIZ];
+ char display_name[SIZ];
+ char *mptr;
+ char *nl; /* newline string */
+
+ /* buffers needed for RFC822 translation */
+ char suser[SIZ];
+ char luser[SIZ];
+ char fuser[SIZ];
+ char snode[SIZ];
+ char lnode[SIZ];
+ char mid[SIZ];
+ char datestamp[SIZ];
+ /* */
+
+ sprintf(mid, "%ld", msg_num);
+ nl = (crlf ? "\r\n" : "\n");
+
+ if (!is_valid_message(TheMessage)) {
+ lprintf(1, "ERROR: invalid preloaded message for output\n");
+ return(om_no_such_msg);
}
/* Are we downloading a MIME component? */
if (mode == MT_DOWNLOAD) {
if (TheMessage->cm_format_type != FMT_RFC822) {
- cprintf("%d This is not a MIME message.\n",
+ if (do_proto)
+ cprintf("%d This is not a MIME message.\n",
ERROR);
} else if (CC->download_fp != NULL) {
- cprintf("%d You already have a download open.\n",
+ if (do_proto) cprintf(
+ "%d You already have a download open.\n",
ERROR);
} else {
/* Parse the message text component */
mptr = TheMessage->cm_fields['M'];
- mime_parser(mptr, NULL, *mime_download);
+ mime_parser(mptr, NULL,
+ *mime_download, NULL, NULL,
+ NULL, 0);
/* If there's no file open by this time, the requested
* section wasn't found, so print an error
*/
if (CC->download_fp == NULL) {
- cprintf("%d Section %s not found.\n",
+ if (do_proto) cprintf(
+ "%d Section %s not found.\n",
ERROR + FILE_NOT_FOUND,
desired_section);
}
}
- CtdlFreeMessage(TheMessage);
- return;
+ return((CC->download_fp != NULL) ? om_ok : om_mime_error);
}
/* now for the user-mode message reading loops */
- cprintf("%d Message %ld:\n", LISTING_FOLLOWS, msg_num);
+ if (do_proto) cprintf("%d Message %ld:\n", LISTING_FOLLOWS, msg_num);
/* Tell the client which format type we're using. If this is a
* MIME message, *lie* about it and tell the user it's fixed-format.
*/
if (mode == MT_CITADEL) {
- if (TheMessage->cm_format_type == FMT_RFC822)
- cprintf("type=1\n");
- else
- cprintf("type=%d\n", TheMessage->cm_format_type);
+ if (TheMessage->cm_format_type == FMT_RFC822) {
+ if (do_proto) cprintf("type=1\n");
+ }
+ else {
+ if (do_proto) cprintf("type=%d\n",
+ TheMessage->cm_format_type);
+ }
}
/* nhdr=yes means that we're only displaying headers, no body */
if ((TheMessage->cm_anon_type == MES_ANON) && (mode == MT_CITADEL)) {
- cprintf("nhdr=yes\n");
+ if (do_proto) cprintf("nhdr=yes\n");
}
/* begin header processing loop for Citadel message format */
if (k != 'M') {
if (TheMessage->cm_fields[k] != NULL) {
if (k == 'A') {
- cprintf("%s=%s\n",
+ if (do_proto) cprintf("%s=%s\n",
msgkeys[k],
display_name);
}
else {
- cprintf("%s=%s\n",
+ if (do_proto) cprintf("%s=%s\n",
msgkeys[k],
TheMessage->cm_fields[k]
);
strcpy(suser, "");
strcpy(luser, "");
+ strcpy(fuser, "");
strcpy(snode, NODENAME);
strcpy(lnode, HUMANNODE);
if (mode == MT_RFC822) {
+ cprintf("X-UIDL: %ld%s", msg_num, nl);
for (i = 0; i < 256; ++i) {
if (TheMessage->cm_fields[i]) {
mptr = TheMessage->cm_fields[i];
if (i == 'A') {
strcpy(luser, mptr);
- } else if (i == 'P') {
- cprintf("Path: %s\n", mptr);
- for (a = 0; a < strlen(mptr); ++a) {
- if (mptr[a] == '!') {
- strcpy(mptr, &mptr[a + 1]);
- a = 0;
- }
- }
strcpy(suser, mptr);
- } else if (i == 'U')
- cprintf("Subject: %s\n", mptr);
+ }
+/****
+ "Path:" removed for now because it confuses brain-dead Microsoft shitware
+ into thinking that mail messages are newsgroup messages instead. When we
+ add NNTP support back into Citadel we'll have to add code to only output
+ this field when appropriate.
+ else if (i == 'P') {
+ cprintf("Path: %s%s", mptr, nl);
+ }
+ ****/
+ else if (i == 'U')
+ cprintf("Subject: %s%s", mptr, nl);
else if (i == 'I')
strcpy(mid, mptr);
else if (i == 'H')
strcpy(lnode, mptr);
else if (i == 'O')
- cprintf("X-Citadel-Room: %s\n", mptr);
+ cprintf("X-Citadel-Room: %s%s",
+ mptr, nl);
else if (i == 'N')
strcpy(snode, mptr);
else if (i == 'R')
- cprintf("To: %s\n", mptr);
+ cprintf("To: %s%s", mptr, nl);
else if (i == 'T') {
- xtime = atol(mptr);
- cprintf("Date: %s", asctime(localtime(&xtime)));
+ datestring(datestamp, atol(mptr),
+ DATESTRING_RFC822 );
+ cprintf("Date: %s%s", datestamp, nl);
}
}
}
}
+ for (i=0; i<strlen(suser); ++i) {
+ suser[i] = tolower(suser[i]);
+ if (!isalnum(suser[i])) suser[i]='_';
+ }
+
if (mode == MT_RFC822) {
if (!strcasecmp(snode, NODENAME)) {
strcpy(snode, FQDN);
}
- cprintf("Message-ID: <%s@%s>\n", mid, snode);
+
+ /* Construct a fun message id */
+ cprintf("Message-ID: <%s", mid);
+ if (strchr(mid, '@')==NULL) {
+ cprintf("@%s", snode);
+ }
+ cprintf(">%s", nl);
+
PerformUserHooks(luser, (-1L), EVT_OUTPUTMSG);
- cprintf("From: %s@%s (%s)\n", suser, snode, luser);
- cprintf("Organization: %s\n", lnode);
+
+ if (strlen(fuser) > 0) {
+ cprintf("From: %s (%s)%s", fuser, luser, nl);
+ }
+ else {
+ cprintf("From: %s@%s (%s)%s", suser, snode, luser, nl);
+ }
+
+ cprintf("Organization: %s%s", lnode, nl);
}
/* end header processing loop ... at this point, we're in the text */
mptr = TheMessage->cm_fields['M'];
/* Tell the client about the MIME parts in this message */
- if (TheMessage->cm_format_type == FMT_RFC822) { /* legacy text dump */
+ if (TheMessage->cm_format_type == FMT_RFC822) {
if (mode == MT_CITADEL) {
- mime_parser(mptr, NULL, *list_this_part);
+ mime_parser(mptr, NULL,
+ *list_this_part, NULL, NULL,
+ NULL, 0);
}
else if (mode == MT_MIME) { /* list parts only */
- mime_parser(mptr, NULL, *list_this_part);
- cprintf("000\n");
- CtdlFreeMessage(TheMessage);
- return;
+ mime_parser(mptr, NULL,
+ *list_this_part, NULL, NULL,
+ NULL, 0);
+ if (do_proto) cprintf("000\n");
+ return(om_ok);
+ }
+ else if (mode == MT_RFC822) { /* unparsed RFC822 dump */
+ /* FIXME ... we have to put some code in here to avoid
+ * printing duplicate header information when both
+ * Citadel and RFC822 headers exist. Preference should
+ * probably be given to the RFC822 headers.
+ */
+ while (ch=*(mptr++), ch!=0) {
+ if (ch==13) ;
+ else if (ch==10) cprintf("%s", nl);
+ else cprintf("%c", ch);
+ }
+ if (do_proto) cprintf("000\n");
+ return(om_ok);
}
}
if (headers_only) {
- cprintf("000\n");
- CtdlFreeMessage(TheMessage);
- return;
+ if (do_proto) cprintf("000\n");
+ return(om_ok);
}
/* signify start of msg text */
if (mode == MT_CITADEL)
- cprintf("text\n");
- if ((mode == MT_RFC822) && (TheMessage->cm_format_type != FMT_RFC822))
- cprintf("\n");
+ if (do_proto) cprintf("text\n");
+ if (mode == MT_RFC822) {
+ if (TheMessage->cm_fields['U'] == NULL) {
+ cprintf("Subject: (no subject)%s", nl);
+ }
+ cprintf("%s", nl);
+ }
/* If the format type on disk is 1 (fixed-format), then we want
* everything to be output completely literally ... regardless of
if (ch == 13)
ch = 10;
if ((ch == 10) || (strlen(buf) > 250)) {
- cprintf("%s\n", buf);
+ cprintf("%s%s", buf, nl);
strcpy(buf, "");
} else {
buf[strlen(buf) + 1] = 0;
}
}
if (strlen(buf) > 0)
- cprintf("%s\n", buf);
+ cprintf("%s%s", buf, nl);
}
/* If the message on disk is format 0 (Citadel vari-format), we
* message to the reader's screen width.
*/
if (TheMessage->cm_format_type == FMT_CITADEL) {
- memfmout(80, mptr, 0);
+ memfmout(80, mptr, 0, nl);
}
/* If the message on disk is format 4 (MIME), we've gotta hand it
if (TheMessage->cm_format_type == FMT_RFC822) {
CtdlAllocUserData(SYM_MA_INFO, sizeof(struct ma_info));
memset(ma, 0, sizeof(struct ma_info));
- mime_parser(mptr, NULL, *fixed_output);
+ mime_parser(mptr, NULL,
+ *fixed_output, NULL, NULL,
+ NULL, 0);
}
/* now we're done */
- cprintf("000\n");
- CtdlFreeMessage(TheMessage);
- return;
+ if (do_proto) cprintf("000\n");
+ return(om_ok);
}
*/
void cmd_msg0(char *cmdbuf)
{
- char msgid[256];
+ long msgid;
int headers_only = 0;
- extract(msgid, cmdbuf, 0);
+ msgid = extract_long(cmdbuf, 0);
headers_only = extract_int(cmdbuf, 1);
- output_message(msgid, MT_CITADEL, headers_only);
+ CtdlOutputMsg(msgid, MT_CITADEL, headers_only, 1, 0);
return;
}
*/
void cmd_msg2(char *cmdbuf)
{
- char msgid[256];
+ long msgid;
int headers_only = 0;
- extract(msgid, cmdbuf, 0);
+ msgid = extract_long(cmdbuf, 0);
headers_only = extract_int(cmdbuf, 1);
- output_message(msgid, MT_RFC822, headers_only);
+ CtdlOutputMsg(msgid, MT_RFC822, headers_only, 1, 1);
}
/*
- * display a message (mode 4 - MIME) (FIX ... still evolving, not complete)
+ * display a message (mode 4 - MIME) (FIXME ... still evolving, not complete)
*/
void cmd_msg4(char *cmdbuf)
{
- char msgid[256];
-
- extract(msgid, cmdbuf, 0);
+ long msgid;
- output_message(msgid, MT_MIME, 0);
+ msgid = extract_long(cmdbuf, 0);
+ CtdlOutputMsg(msgid, MT_MIME, 0, 1, 0);
}
/*
*/
void cmd_opna(char *cmdbuf)
{
- char msgid[256];
+ long msgid;
- CtdlAllocUserData(SYM_DESIRED_SECTION, 64);
+ CtdlAllocUserData(SYM_DESIRED_SECTION, SIZ);
- extract(msgid, cmdbuf, 0);
+ msgid = extract_long(cmdbuf, 0);
extract(desired_section, cmdbuf, 1);
- output_message(msgid, MT_DOWNLOAD, 0);
+ CtdlOutputMsg(msgid, MT_DOWNLOAD, 0, 1, 1);
}
getroom(&CC->quickroom, hold_rm);
/* Bump the reference count for this message. */
- AdjRefCount(msgid, +1);
+ if ((flags & SM_DONT_BUMP_REF)==0) {
+ AdjRefCount(msgid, +1);
+ }
/* Return success. */
if (msg != NULL) CtdlFreeMessage(msg);
*
*/
long send_message(struct CtdlMessage *msg, /* pointer to buffer */
- int generate_id, /* generate 'I' field? */
FILE *save_a_copy) /* save a copy to disk? */
{
long newmsgid;
long retval;
- char msgidbuf[32];
+ char msgidbuf[SIZ];
struct ser_ret smr;
/* Get a new message number */
newmsgid = get_new_message_number();
- sprintf(msgidbuf, "%ld", newmsgid);
+ sprintf(msgidbuf, "%ld@%s", newmsgid, config.c_fqdn);
- if (generate_id) {
+ /* Generate an ID if we don't have one already */
+ if (msg->cm_fields['I']==NULL) {
msg->cm_fields['I'] = strdoop(msgidbuf);
}
}
/* Write our little bundle of joy into the message base */
- begin_critical_section(S_MSGMAIN);
if (cdb_store(CDB_MSGMAIN, &newmsgid, sizeof(long),
smr.ser, smr.len) < 0) {
lprintf(2, "Can't store message\n");
} else {
retval = newmsgid;
}
- end_critical_section(S_MSGMAIN);
/* If the caller specified that a copy should be saved to a particular
* file handle, do that now too.
ret->len = ret->len +
strlen(msg->cm_fields[(int)forder[i]]) + 2;
- lprintf(9, "calling malloc\n");
+ lprintf(9, "serialize_message() calling malloc(%d)\n", ret->len);
ret->ser = mallok(ret->len);
if (ret->ser == NULL) {
ret->len = 0;
/*
* Back end for the ReplicationChecks() function
*/
-void check_repl(long msgnum) {
+void check_repl(long msgnum, void *userdata) {
struct CtdlMessage *msg;
time_t timestamp = (-1L);
lprintf(9, "older!\n");
/* Existing isn't newer? Then delete the old one(s). */
- CtdlDeleteMessages(CC->quickroom.QRname, msgnum, NULL);
+ CtdlDeleteMessages(CC->quickroom.QRname, msgnum, "");
}
memset(template, 0, sizeof(struct CtdlMessage));
template->cm_fields['E'] = strdoop(msg->cm_fields['E']);
- CtdlForEachMessage(MSGS_ALL, 0L, NULL, template, check_repl);
+ CtdlForEachMessage(MSGS_ALL, 0L, (-127), NULL, template,
+ check_repl, NULL);
/* If a newer message exists with the same Extended ID, abort
* this save.
long CtdlSaveMsg(struct CtdlMessage *msg, /* message to save */
char *rec, /* Recipient (mail) */
char *force, /* force a particular room? */
- int mailtype, /* local or remote type */
- int generate_id) /* 1 = generate 'I' field */
+ int supplied_mailtype) /* local or remote type */
{
char aaa[100];
char hold_rm[ROOMNAMELEN];
char actual_rm[ROOMNAMELEN];
char force_room[ROOMNAMELEN];
- char content_type[256]; /* We have to learn this */
- char recipient[256];
+ char content_type[SIZ]; /* We have to learn this */
+ char recipient[SIZ];
long newmsgid;
char *mptr = NULL;
struct usersupp userbuf;
struct SuppMsgInfo smi;
FILE *network_fp = NULL;
static int seqnum = 1;
+ struct CtdlMessage *imsg;
+ char *instr;
+ int mailtype;
lprintf(9, "CtdlSaveMsg() called\n");
if (is_valid_message(msg) == 0) return(-1); /* self check */
+ mailtype = supplied_mailtype;
/* If this message has no timestamp, we take the liberty of
* giving it one, right now.
strcpy(force_room, force);
/* Strip non-printable characters out of the recipient name */
+ lprintf(9, "Checking recipient (if present)\n");
strcpy(recipient, rec);
for (a = 0; a < strlen(recipient); ++a)
if (!isprint(recipient[a]))
strcpy(&recipient[a], &recipient[a + 1]);
+ /* Change "user @ xxx" to "user" if xxx is an alias for this host */
+ for (a=0; a<strlen(recipient); ++a) {
+ if (recipient[a] == '@') {
+ if (CtdlHostAlias(&recipient[a+1])
+ == hostalias_localhost) {
+ recipient[a] = 0;
+ lprintf(7, "Changed to <%s>\n", recipient);
+ mailtype = MES_LOCAL;
+ }
+ }
+ }
+
+ lprintf(9, "Recipient is <%s>\n", recipient);
+
/* Learn about what's inside, because it's what's inside that counts */
lprintf(9, "Learning what's inside\n");
if (msg->cm_fields['M'] == NULL) {
/* advance past header fields */
mptr = msg->cm_fields['M'];
a = strlen(mptr);
- while (--a) {
+ while ((--a) > 0) {
if (!strncasecmp(mptr, "Content-type: ", 14)) {
safestrncpy(content_type, mptr,
sizeof(content_type));
}
lprintf(9, "Possibly relocating\n");
- if (strcasecmp(actual_rm, CC->quickroom.QRname))
+ if (strcasecmp(actual_rm, CC->quickroom.QRname)) {
getroom(&CC->quickroom, actual_rm);
+ }
+
+ /*
+ * If this message has no O (room) field, generate one.
+ */
+ if (msg->cm_fields['O'] == NULL) {
+ msg->cm_fields['O'] = strdoop(CC->quickroom.QRname);
+ }
/* Perform "before save" hooks (aborting if any return nonzero) */
lprintf(9, "Performing before-save hooks\n");
/* Save it to disk */
lprintf(9, "Saving to disk\n");
- newmsgid = send_message(msg, generate_id, network_fp);
+ newmsgid = send_message(msg, network_fp);
if (network_fp != NULL) {
fclose(network_fp);
system("exec nohup ./netproc -i >/dev/null 2>&1 &");
/* Now figure out where to store the pointers */
lprintf(9, "Storing pointers\n");
-
/* If this is being done by the networker delivering a private
* message, we want to BYPASS saving the sender's copy (because there
* is no local sender; it would otherwise go to the Trashcan).
*/
if ((!CC->internal_pgm) || (strlen(recipient) == 0)) {
- CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 0);
+ if (CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 0) != 0) {
+ lprintf(3, "ERROR saving message pointer!\n");
+ CtdlSaveMsgPointerInRoom(AIDEROOM, newmsgid, 0);
+ }
}
/* For internet mail, drop a copy in the outbound queue room */
- /* FIX ... nothing's going to get delivered until we add
- some delivery instructions!!! */
if (mailtype == MES_INTERNET) {
CtdlSaveMsgPointerInRoom(SMTP_SPOOLOUT_ROOM, newmsgid, 0);
}
MailboxName(actual_rm, &userbuf, MAILROOM);
CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 0);
}
+ else {
+ lprintf(9, "No user <%s>, saving in %s> instead\n",
+ recipient, AIDEROOM);
+ CtdlSaveMsgPointerInRoom(AIDEROOM, newmsgid, 0);
+ }
}
/* Perform "after save" hooks */
if (strcasecmp(hold_rm, CC->quickroom.QRname))
getroom(&CC->quickroom, hold_rm);
+ /* For internet mail, generate delivery instructions
+ * (Yes, this is recursive! Deal with it!)
+ */
+ if (mailtype == MES_INTERNET) {
+ lprintf(9, "Generating delivery instructions\n");
+ instr = mallok(2048);
+ sprintf(instr,
+ "Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n"
+ "bounceto|%s@%s\n"
+ "remote|%s|0||\n",
+ SPOOLMIME, newmsgid, time(NULL),
+ msg->cm_fields['A'], msg->cm_fields['N'],
+ recipient );
+
+ imsg = mallok(sizeof(struct CtdlMessage));
+ memset(imsg, 0, sizeof(struct CtdlMessage));
+ imsg->cm_magic = CTDLMESSAGE_MAGIC;
+ imsg->cm_anon_type = MES_NORMAL;
+ imsg->cm_format_type = FMT_RFC822;
+ imsg->cm_fields['A'] = strdoop("Citadel");
+ imsg->cm_fields['M'] = instr;
+ CtdlSaveMsg(imsg, "", SMTP_SPOOLOUT_ROOM, MES_LOCAL);
+ CtdlFreeMessage(imsg);
+ }
+
return(newmsgid);
}
msg->cm_fields['R'] = strdoop(to);
msg->cm_fields['M'] = strdoop(text);
- CtdlSaveMsg(msg, "", room, MES_LOCAL, 1);
+ CtdlSaveMsg(msg, "", room, MES_LOCAL);
CtdlFreeMessage(msg);
syslog(LOG_NOTICE, text);
}
char *exist /* if non-null, append to it;
exist is ALWAYS freed */
) {
- char buf[256];
+ char buf[SIZ];
+ int linelen;
size_t message_len = 0;
size_t buffer_len = 0;
- char *ptr, *append;
+ char *ptr;
char *m;
if (exist == NULL) {
message_len = 0;
}
/* read in the lines of message text one by one */
- append = NULL;
while ( (client_gets(buf)>0) && strcmp(buf, terminator) ) {
+ /* strip trailing newline type stuff */
+ if (buf[strlen(buf)-1]==10) buf[strlen(buf)-1]=0;
+ if (buf[strlen(buf)-1]==13) buf[strlen(buf)-1]=0;
+
+ linelen = strlen(buf);
+
/* augment the buffer if we have to */
- if ((message_len + strlen(buf) + 2) > buffer_len) {
+ if ((message_len + linelen + 2) > buffer_len) {
lprintf(9, "realloking\n");
ptr = reallok(m, (buffer_len * 2) );
if (ptr == NULL) { /* flush if can't allocate */
} else {
buffer_len = (buffer_len * 2);
m = ptr;
- append = NULL;
lprintf(9, "buffer_len is %d\n", buffer_len);
}
}
- if (append == NULL) append = m;
- while (strlen(append) > 0) ++append;
- strcpy(append, buf);
- strcat(append, "\n");
- message_len = message_len + strlen(buf) + 1;
+ /* Add the new line to the buffer. We avoid using strcat()
+ * because that would involve traversing the entire message
+ * after each line, and this function needs to run fast.
+ */
+ strcpy(&m[message_len], buf);
+ m[message_len + linelen] = '\n';
+ m[message_len + linelen + 1] = 0;
+ message_len = message_len + linelen + 1;
/* if we've hit the max msg length, flush the rest */
if (message_len >= maxlen) {
- while ( (client_gets(buf)>0) && strcmp(buf, terminator)) ;;
+ while ( (client_gets(buf)>0)
+ && strcmp(buf, terminator)) ;;
return(m);
}
}
int a;
char dest_node[32];
- char buf[256];
+ char buf[SIZ];
struct CtdlMessage *msg;
msg = mallok(sizeof(struct CtdlMessage));
}
+/*
+ * Check to see whether we have permission to post a message in the current
+ * room. Returns a *CITADEL ERROR CODE* and puts a message in errmsgbuf, or
+ * returns 0 on success.
+ */
+int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf) {
+
+ if (!(CC->logged_in)) {
+ sprintf(errmsgbuf, "Not logged in.");
+ return (ERROR + NOT_LOGGED_IN);
+ }
+
+ if ((CC->usersupp.axlevel < 2)
+ && ((CC->quickroom.QRflags & QR_MAILBOX) == 0)) {
+ sprintf(errmsgbuf, "Need to be validated to enter "
+ "(except in %s> to sysop)", MAILROOM);
+ return (ERROR + HIGHER_ACCESS_REQUIRED);
+ }
+
+ if ((CC->usersupp.axlevel < 4)
+ && (CC->quickroom.QRflags & QR_NETWORK)) {
+ sprintf(errmsgbuf, "Need net privileges to enter here.");
+ return (ERROR + HIGHER_ACCESS_REQUIRED);
+ }
+
+ if ((CC->usersupp.axlevel < 6)
+ && (CC->quickroom.QRflags & QR_READONLY)) {
+ sprintf(errmsgbuf, "Sorry, this is a read-only room.");
+ return (ERROR + HIGHER_ACCESS_REQUIRED);
+ }
+
+ strcpy(errmsgbuf, "Ok");
+ return(0);
+}
+
void cmd_ent0(char *entargs)
{
int post = 0;
- char recipient[256];
+ char recipient[SIZ];
int anon_flag = 0;
int format_type = 0;
- char newusername[256];
+ char newusername[SIZ];
struct CtdlMessage *msg;
int a, b;
int e = 0;
int mtsflag = 0;
struct usersupp tempUS;
- char buf[256];
+ char buf[SIZ];
+ int err = 0;
post = extract_int(entargs, 0);
extract(recipient, entargs, 1);
/* first check to make sure the request is valid. */
- if (!(CC->logged_in)) {
- cprintf("%d Not logged in.\n", ERROR + NOT_LOGGED_IN);
- return;
- }
- if ((CC->usersupp.axlevel < 2) && ((CC->quickroom.QRflags & QR_MAILBOX) == 0)) {
- cprintf("%d Need to be validated to enter ",
- ERROR + HIGHER_ACCESS_REQUIRED);
- cprintf("(except in %s> to sysop)\n", MAILROOM);
- return;
- }
- if ((CC->usersupp.axlevel < 4) && (CC->quickroom.QRflags & QR_NETWORK)) {
- cprintf("%d Need net privileges to enter here.\n",
- ERROR + HIGHER_ACCESS_REQUIRED);
+ err = CtdlDoIHavePermissionToPostInThisRoom(buf);
+ if (err) {
+ cprintf("%d %s\n", err, buf);
return;
}
- if ((CC->usersupp.axlevel < 6) && (CC->quickroom.QRflags & QR_READONLY)) {
- cprintf("%d Sorry, this is a read-only room.\n",
- ERROR + HIGHER_ACCESS_REQUIRED);
- return;
- }
- mtsflag = 0;
+ /* Check some other permission type things. */
if (post == 2) {
if (CC->usersupp.axlevel < 6) {
}
if (!strcasecmp(buf, "sysop")) {
mtsflag = 1;
- goto SKFALL;
- }
- if (e != MES_LOCAL)
- goto SKFALL; /* don't search local file */
- if (!strcasecmp(buf, CC->usersupp.fullname)) {
- cprintf("%d Can't send mail to yourself!\n",
- ERROR + NO_SUCH_USER);
- return;
}
- /* Check to make sure the user exists; also get the correct
- * upper/lower casing of the name.
- */
- a = getuser(&tempUS, buf);
- if (a != 0) {
- cprintf("%d No such user.\n", ERROR + NO_SUCH_USER);
- return;
+ else if (e == MES_LOCAL) { /* don't search local file */
+ if (!strcasecmp(buf, CC->usersupp.fullname)) {
+ cprintf("%d Can't send mail to yourself!\n",
+ ERROR + NO_SUCH_USER);
+ return;
+ }
+ /* Check to make sure the user exists; also get the correct
+ * upper/lower casing of the name.
+ */
+ a = getuser(&tempUS, buf);
+ if (a != 0) {
+ cprintf("%d No such user.\n", ERROR + NO_SUCH_USER);
+ return;
+ }
+ strcpy(buf, tempUS.fullname);
}
- strcpy(buf, tempUS.fullname);
}
-SKFALL: b = MES_NORMAL;
+ b = MES_NORMAL;
if (CC->quickroom.QRflags & QR_ANONONLY)
b = MES_ANON;
if (CC->quickroom.QRflags & QR_ANONOPT) {
CC->quickroom.QRname, b, e, format_type, "");
if (msg != NULL)
- CtdlSaveMsg(msg, buf, (mtsflag ? AIDEROOM : ""), e, 1);
+ CtdlSaveMsg(msg, buf, (mtsflag ? AIDEROOM : ""), e);
CtdlFreeMessage(msg);
CC->fake_postname[0] = '\0';
return;
*/
void cmd_ent3(char *entargs)
{
- char recp[256];
+ char recp[SIZ];
int a;
int e = 0;
int valid_msg = 1;
}
msg->cm_flags = CM_SKIP_HOOKS;
- if (valid_msg) CtdlSaveMsg(msg, recp, "", e, 0);
+ if (valid_msg) CtdlSaveMsg(msg, recp, "", e);
CtdlFreeMessage(msg);
phree(tempbuf);
}
*/
int CtdlDeleteMessages(char *room_name, /* which room */
long dmsgnum, /* or "0" for any */
- char *content_type /* or NULL for any */
+ char *content_type /* or "" for any */
)
{
if ((dmsgnum == 0L) || (msglist[i] == dmsgnum)) {
delete_this |= 0x01;
}
- if (content_type == NULL) {
+ if (strlen(content_type) == 0) {
delete_this |= 0x02;
} else {
GetSuppMsgInfo(&smi, msglist[i]);
+/*
+ * Check whether the current user has permission to delete messages from
+ * the current room (returns 1 for yes, 0 for no)
+ */
+int CtdlDoIHavePermissionToDeleteMessagesFromThisRoom(void) {
+ getuser(&CC->usersupp, CC->curr_user);
+ if ((CC->usersupp.axlevel < 6)
+ && (CC->usersupp.usernum != CC->quickroom.QRroomaide)
+ && ((CC->quickroom.QRflags & QR_MAILBOX) == 0)
+ && (!(CC->internal_pgm))) {
+ return(0);
+ }
+ return(1);
+}
+
+
+
/*
* Delete message from current room
*/
long delnum;
int num_deleted;
- getuser(&CC->usersupp, CC->curr_user);
- if ((CC->usersupp.axlevel < 6)
- && (CC->usersupp.usernum != CC->quickroom.QRroomaide)
- && ((CC->quickroom.QRflags & QR_MAILBOX) == 0)
- && (!(CC->internal_pgm))) {
+ if (CtdlDoIHavePermissionToDeleteMessagesFromThisRoom() == 0) {
cprintf("%d Higher access required.\n",
ERROR + HIGHER_ACCESS_REQUIRED);
return;
}
delnum = extract_long(delstr, 0);
- num_deleted = CtdlDeleteMessages(CC->quickroom.QRname, delnum, NULL);
+ num_deleted = CtdlDeleteMessages(CC->quickroom.QRname, delnum, "");
if (num_deleted) {
cprintf("%d %d message%s deleted.\n", OK,
}
+/*
+ * Back end API function for moves and deletes
+ */
+int CtdlCopyMsgToRoom(long msgnum, char *dest) {
+ int err;
+
+ err = CtdlSaveMsgPointerInRoom(dest, msgnum,
+ (SM_VERIFY_GOODNESS | SM_DO_REPL_CHECK) );
+ if (err != 0) return(err);
+
+ return(0);
+}
+
+
+
/*
* move or copy a message to another room
*/
void cmd_move(char *args)
{
long num;
- char targ[256];
+ char targ[SIZ];
struct quickroom qtemp;
int err;
int is_copy = 0;
return;
}
- err = CtdlSaveMsgPointerInRoom(targ, num,
- (SM_VERIFY_GOODNESS | SM_DO_REPL_CHECK) );
+ err = CtdlCopyMsgToRoom(num, targ);
if (err != 0) {
cprintf("%d Cannot store message in %s: error %d\n",
err, targ, err);
/* Now delete the message from the source room,
* if this is a 'move' rather than a 'copy' operation.
*/
- if (is_copy == 0) CtdlDeleteMessages(CC->quickroom.QRname, num, NULL);
+ if (is_copy == 0) CtdlDeleteMessages(CC->quickroom.QRname, num, "");
cprintf("%d Message %s.\n", OK, (is_copy ? "copied" : "moved") );
}
*/
begin_critical_section(S_SUPPMSGMAIN);
GetSuppMsgInfo(&smi, msgnum);
+ lprintf(9, "Ref count for message <%ld> before write is <%d>\n",
+ msgnum, smi.smi_refcount);
smi.smi_refcount += incr;
PutSuppMsgInfo(&smi);
end_critical_section(S_SUPPMSGMAIN);
-
lprintf(9, "Ref count for message <%ld> after write is <%d>\n",
msgnum, smi.smi_refcount);
FILE *fp, *tempfp;
char filename[PATH_MAX];
- char cmdbuf[256];
- int ch;
+ char cmdbuf[SIZ];
+ char ch;
struct quickroom qrbuf;
char roomname[ROOMNAMELEN];
struct CtdlMessage *msg;
/* Create the requested room if we have to. */
if (getroom(&qrbuf, roomname) != 0) {
- create_room(roomname, 4, "", 0);
+ create_room(roomname,
+ ( (is_mailbox != NULL) ? 5 : 3 ),
+ "", 0, 1);
}
/* If the caller specified this object as unique, delete all
* other objects of this type that are currently in the room.
CtdlDeleteMessages(roomname, 0L, content_type));
}
/* Now write the data */
- CtdlSaveMsg(msg, "", roomname, MES_LOCAL, 1);
+ CtdlSaveMsg(msg, "", roomname, MES_LOCAL);
CtdlFreeMessage(msg);
}
-void CtdlGetSysConfigBackend(long msgnum) {
+void CtdlGetSysConfigBackend(long msgnum, void *userdata) {
config_msgnum = msgnum;
}
long msgnum;
char *conf;
struct CtdlMessage *msg;
- char buf[256];
+ char buf[SIZ];
strcpy(hold_rm, CC->quickroom.QRname);
if (getroom(&CC->quickroom, SYSCONFIGROOM) != 0) {
/* We want the last (and probably only) config in this room */
begin_critical_section(S_CONFIG);
config_msgnum = (-1L);
- CtdlForEachMessage(MSGS_LAST, 1, sysconfname, NULL,
- CtdlGetSysConfigBackend);
+ CtdlForEachMessage(MSGS_LAST, 1, (-127), sysconfname, NULL,
+ CtdlGetSysConfigBackend, NULL);
msgnum = config_msgnum;
end_critical_section(S_CONFIG);
fp = fopen(temp, "w");
if (fp == NULL) return;
- fprintf(fp, "Content-type: %s\n\n", sysconfname);
fprintf(fp, "%s", sysconfdata);
fclose(fp);
/* this handy API function does all the work for us */
- CtdlWriteObject(SYSCONFIGROOM, sysconfname, temp,
- &CC->usersupp, 0, 1, 0);
-
+ CtdlWriteObject(SYSCONFIGROOM, sysconfname, temp, NULL, 0, 1, 0);
unlink(temp);
}
-
-