*
* Implements the message store.
*
+ * Copyright (c) 1987-2010 by the citadel.org team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "sysdep.h"
#include "serv_network.h"
#include "threads.h"
+#include "ctdl_module.h"
+
long config_msgnum;
struct addresses_to_be_filed *atbf = NULL;
CtdlFreeMessage(msg);
}
+/*
+ * Back end for the MSGS command: output EUID header.
+ */
+void headers_euid(long msgnum, void *userdata)
+{
+ struct CtdlMessage *msg;
+
+ msg = CtdlFetchMessage(msgnum, 0);
+ if (msg == NULL) {
+ cprintf("%ld||\n", msgnum);
+ return;
+ }
+
+ cprintf("%ld|%s|\n", msgnum, (msg->cm_fields['E'] ? msg->cm_fields['E'] : ""));
+ CtdlFreeMessage(msg);
+}
+
+
+
/* Determine if a given message matches the fields in a message template.
for (i='A'; i<='Z'; ++i) {
if (template->cm_fields[i] != NULL) {
if (msg->cm_fields[i] == NULL) {
+ /* Considered equal if temmplate is empty string */
+ if (IsEmptyStr(template->cm_fields[i])) continue;
return 1;
}
if (strcasecmp(msg->cm_fields[i],
int target_setting, int which_set,
struct ctdluser *which_user, struct ctdlroom *which_room) {
struct cdbdata *cdbfr;
- int i, j, k;
+ int i, k;
int is_seen = 0;
int was_seen = 0;
long lo = (-1L);
struct visit vbuf;
long *msglist;
int num_msgs = 0;
- char vset[SIZ];
+ StrBuf *vset;
+ StrBuf *setstr;
+ StrBuf *lostr;
+ StrBuf *histr;
+ const char *pvset;
char *is_set; /* actually an array of booleans */
- int num_sets;
- int s;
- int w = 0;
- char setstr[SIZ], lostr[SIZ], histr[SIZ];
/* Don't bother doing *anything* if we were passed a list of zero messages */
if (num_target_msgnums < 1) {
/* Decide which message set we're manipulating */
switch(which_set) {
- case ctdlsetseen_seen:
- safestrncpy(vset, vbuf.v_seen, sizeof vset);
- break;
- case ctdlsetseen_answered:
- safestrncpy(vset, vbuf.v_answered, sizeof vset);
- break;
+ case ctdlsetseen_seen:
+ vset = NewStrBufPlain(vbuf.v_seen, -1);
+ break;
+ case ctdlsetseen_answered:
+ vset = NewStrBufPlain(vbuf.v_answered, -1);
+ break;
+ default:
+ vset = NewStrBuf();
}
}
#endif
- CtdlLogPrintf(CTDL_DEBUG, "before update: %s\n", vset);
+ CtdlLogPrintf(CTDL_DEBUG, "before update: %s\n", ChrPtr(vset));
/* Translate the existing sequence set into an array of booleans */
- num_sets = num_tokens(vset, ',');
- for (s=0; s<num_sets; ++s) {
- extract_token(setstr, vset, s, ',', sizeof setstr);
-
- extract_token(lostr, setstr, 0, ':', sizeof lostr);
- if (num_tokens(setstr, ':') >= 2) {
- extract_token(histr, setstr, 1, ':', sizeof histr);
+ setstr = NewStrBuf();
+ lostr = NewStrBuf();
+ histr = NewStrBuf();
+ pvset = NULL;
+ while (StrBufExtract_NextToken(setstr, vset, &pvset, ',') >= 0) {
+
+ StrBufExtract_token(lostr, setstr, 0, ':');
+ if (StrBufNum_tokens(setstr, ':') >= 2) {
+ StrBufExtract_token(histr, setstr, 1, ':');
}
else {
- strcpy(histr, lostr);
+ FlushStrBuf(histr);
+ StrBufAppendBuf(histr, lostr, 0);
}
- lo = atol(lostr);
- if (!strcmp(histr, "*")) {
+ lo = StrTol(lostr);
+ if (!strcmp(ChrPtr(histr), "*")) {
hi = LONG_MAX;
}
else {
- hi = atol(histr);
+ hi = StrTol(histr);
}
for (i = 0; i < num_msgs; ++i) {
}
}
}
+ FreeStrBuf(&setstr);
+ FreeStrBuf(&lostr);
+ FreeStrBuf(&histr);
/* Now translate the array of booleans back into a sequence set */
- strcpy(vset, "");
+ FlushStrBuf(vset);
was_seen = 0;
lo = (-1);
hi = (-1);
}
}
- w = 0; /* set to 1 if we write something to the string */
-
if ((was_seen == 0) && (is_seen == 1)) {
lo = msglist[i];
}
else if ((was_seen == 1) && (is_seen == 0)) {
hi = msglist[i-1];
- w = 1;
- if (!IsEmptyStr(vset)) {
- strcat(vset, ",");
+ if (StrLength(vset) > 0) {
+ StrBufAppendBufPlain(vset, HKEY(","), 0);
}
if (lo == hi) {
- sprintf(&vset[strlen(vset)], "%ld", hi);
+ StrBufAppendPrintf(vset, "%ld", hi);
}
else {
- sprintf(&vset[strlen(vset)], "%ld:%ld", lo, hi);
+ StrBufAppendPrintf(vset, "%ld:%ld", lo, hi);
}
}
- else if ((is_seen) && (i == num_msgs - 1)) {
- w = 1;
- if (!IsEmptyStr(vset)) {
- strcat(vset, ",");
+
+ if ((is_seen) && (i == num_msgs - 1)) {
+ if (StrLength(vset) > 0) {
+ StrBufAppendBufPlain(vset, HKEY(","), 0);
}
if ((i==0) || (was_seen == 0)) {
- sprintf(&vset[strlen(vset)], "%ld", msglist[i]);
+ StrBufAppendPrintf(vset, "%ld", msglist[i]);
}
else {
- sprintf(&vset[strlen(vset)], "%ld:%ld", lo, msglist[i]);
+ StrBufAppendPrintf(vset, "%ld:%ld", lo, msglist[i]);
}
}
- /* If the string is getting too long, truncate it at the beginning; repeat up to 9 times */
- if (w) for (j=0; j<9; ++j) {
- if ((strlen(vset) + 20) > sizeof vset) {
- remove_token(vset, 0, ',');
- if (which_set == ctdlsetseen_seen) {
- char temp[SIZ];
- sprintf(temp, "1:%ld,", atol(vset)-1L);
- strcat(temp, vset);
- strcpy(vset, temp);
- }
- }
+ was_seen = is_seen;
+ }
+
+ /*
+ * We will have to stuff this string back into a 4096 byte buffer, so if it's
+ * larger than that now, truncate it by removing tokens from the beginning.
+ * The limit of 100 iterations is there to prevent an infinite loop in case
+ * something unexpected happens.
+ */
+ int number_of_truncations = 0;
+ while ( (StrLength(vset) > SIZ) && (number_of_truncations < 100) ) {
+ StrBufRemove_token(vset, 0, ',');
+ ++number_of_truncations;
+ }
+
+ /*
+ * If we're truncating the sequence set of messages marked with the 'seen' flag,
+ * we want the earliest messages (the truncated ones) to be marked, not unmarked.
+ * Otherwise messages at the beginning will suddenly appear to be 'unseen'.
+ */
+ if ( (which_set == ctdlsetseen_seen) && (number_of_truncations > 0) ) {
+ StrBuf *first_tok;
+ first_tok = NewStrBuf();
+ StrBufExtract_token(first_tok, vset, 0, ',');
+ StrBufRemove_token(vset, 0, ',');
+
+ if (StrBufNum_tokens(first_tok, ':') > 1) {
+ StrBufRemove_token(first_tok, 0, ':');
}
+
+ StrBuf *new_set;
+ new_set = NewStrBuf();
+ StrBufAppendBufPlain(new_set, HKEY("1:"), 0);
+ StrBufAppendBuf(new_set, first_tok, 0);
+ StrBufAppendBufPlain(new_set, HKEY(":"), 0);
+ StrBufAppendBuf(new_set, vset, 0);
- was_seen = is_seen;
+ FreeStrBuf(&vset);
+ FreeStrBuf(&first_tok);
+ vset = new_set;
}
- CtdlLogPrintf(CTDL_DEBUG, " after update: %s\n", vset);
+ CtdlLogPrintf(CTDL_DEBUG, " after update: %s\n", ChrPtr(vset));
/* Decide which message set we're manipulating */
switch (which_set) {
case ctdlsetseen_seen:
- safestrncpy(vbuf.v_seen, vset, sizeof vbuf.v_seen);
+ safestrncpy(vbuf.v_seen, ChrPtr(vset), sizeof vbuf.v_seen);
break;
case ctdlsetseen_answered:
- safestrncpy(vbuf.v_answered, vset, sizeof vbuf.v_answered);
+ safestrncpy(vbuf.v_answered, ChrPtr(vset), sizeof vbuf.v_answered);
break;
}
free(is_set);
free(msglist);
CtdlSetRelationship(&vbuf, which_user, which_room);
+ FreeStrBuf(&vset);
}
int CtdlForEachMessage(int mode, long ref, char *search_string,
char *content_type,
struct CtdlMessage *compare,
- void (*CallBack) (long, void *),
+ ForEachMsgCallback CallBack,
void *userdata)
{
}
/* Learn about the user and room in question */
- getuser(&CC->user, CC->curr_user);
+ CtdlGetUser(&CC->user, CC->curr_user);
CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
/* Load the message list */
|| ((mode == MSGS_LAST) && (a >= (num_msgs - ref)))
|| ((mode == MSGS_FIRST) && (a < ref))
|| ((mode == MSGS_GT) && (thismsg > ref))
+ || ((mode == MSGS_LT) && (thismsg < ref))
|| ((mode == MSGS_EQ) && (thismsg == ref))
)
) {
int i;
int with_template = 0;
struct CtdlMessage *template = NULL;
- int with_headers = 0;
char search_string[1024];
+ ForEachMsgCallback CallBack;
extract_token(which, cmdbuf, 0, '|', sizeof which);
cm_ref = extract_int(cmdbuf, 1);
extract_token(search_string, cmdbuf, 1, '|', sizeof search_string);
with_template = extract_int(cmdbuf, 2);
- with_headers = extract_int(cmdbuf, 3);
+ switch (extract_int(cmdbuf, 3))
+ {
+ default:
+ case MSG_HDRS_BRIEF:
+ CallBack = simple_listing;
+ break;
+ case MSG_HDRS_ALL:
+ CallBack = headers_listing;
+ break;
+ case MSG_HDRS_EUID:
+ CallBack = headers_euid;
+ break;
+ }
strcat(which, " ");
if (!strncasecmp(which, "OLD", 3))
mode = MSGS_LAST;
else if (!strncasecmp(which, "GT", 2))
mode = MSGS_GT;
+ else if (!strncasecmp(which, "LT", 2))
+ mode = MSGS_LT;
else if (!strncasecmp(which, "SEARCH", 6))
mode = MSGS_SEARCH;
else
}
CtdlForEachMessage(mode,
- ( (mode == MSGS_SEARCH) ? 0 : cm_ref ),
- ( (mode == MSGS_SEARCH) ? search_string : NULL ),
- NULL,
- template,
- (with_headers ? headers_listing : simple_listing),
- NULL
- );
+ ( (mode == MSGS_SEARCH) ? 0 : cm_ref ),
+ ( (mode == MSGS_SEARCH) ? search_string : NULL ),
+ NULL,
+ template,
+ CallBack,
+ NULL);
if (template != NULL) CtdlFreeMessage(template);
cprintf("000\n");
}
*/
void memfmout(
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_uint8_t ch;
- char aaa[140];
- char buffer[SIZ];
- static int width = 80;
-
- strcpy(aaa, "");
- old = 255;
- strcpy(buffer, "");
- c = 1; /* c is the current pos */
-
- do {
- 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);
-
- buffer[strlen(buffer) + 1] = 0;
- a = buffer[0];
- strcpy(buffer, &buffer[1]);
- } else {
- ch = *mptr++;
- }
-
- old = real;
- real = ch;
-
- if (((ch == 13) || (ch == 10)) && (old != 13) && (old != 10)) {
- ch = 32;
+ const char *nl /* string to terminate lines with */
+) {
+ int column = 0;
+ char ch = 0;
+ char outbuf[1024];
+ int len = 0;
+ int nllen = 0;
+
+ if (!mptr) return;
+ nllen = strlen(nl);
+ while (ch=*(mptr++), ch > 0) {
+
+ if (ch == '\n') {
+ client_write(outbuf, len);
+ len = 0;
+ client_write(nl, nllen);
+ column = 0;
}
- if (((old == 13) || (old == 10)) && (isspace(real))) {
- cprintf("%s", nl);
- c = 1;
+ else if (ch == '\r') {
+ /* Ignore carriage returns. Newlines are always LF or CRLF but never CR. */
}
- if (ch > 32) {
- if (((strlen(aaa) + c) > (width - 5)) && (strlen(aaa) > (width - 5))) {
- cprintf("%s%s", nl, aaa);
- c = strlen(aaa);
- aaa[0] = 0;
+ else if (isspace(ch)) {
+ if (column > 72) { /* Beyond 72 columns, break on the next space */
+ client_write(outbuf, len);
+ len = 0;
+ client_write(nl, nllen);
+ column = 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;
+ else {
+ outbuf[len++] = ch;
+ ++column;
}
- cprintf("%s ", aaa);
- ++c;
- c = c + strlen(aaa);
- strcpy(aaa, "");
}
- if ((ch == 13) || (ch == 10)) {
- cprintf("%s%s", aaa, nl);
- c = 1;
- strcpy(aaa, "");
+ else {
+ outbuf[len++] = ch;
+ ++column;
+ if (column > 1000) { /* Beyond 1000 columns, break anywhere */
+ client_write(outbuf, len);
+ len = 0;
+ client_write(nl, nllen);
+ column = 0;
+ }
}
-
- } while (ch > 0);
-
- cprintf("%s%s", aaa, nl);
+ }
+ if (len) {
+ client_write(outbuf, len);
+ len = 0;
+ client_write(nl, nllen);
+ column = 0;
+ }
}
ma = (struct ma_info *)cbuserdata;
if (ma->is_ma == 0) {
- cprintf("part=%s|%s|%s|%s|%s|%ld|%s\n",
- name, filename, partnum, disp, cbtype, (long)length, cbid);
+ cprintf("part=%s|%s|%s|%s|%s|%ld|%s|%s\n",
+ name,
+ filename,
+ partnum,
+ disp,
+ cbtype,
+ (long)length,
+ cbid,
+ cbcharset);
}
}
void *content, char *cbtype, char *cbcharset, size_t length,
char *encoding, char *cbid, void *cbuserdata)
{
+ int rv = 0;
/* Silently go away if there's already a download open. */
if (CC->download_fp != NULL)
if (CC->download_fp == NULL)
return;
- fwrite(content, length, 1, CC->download_fp);
+ rv = fwrite(content, length, 1, CC->download_fp);
fflush(CC->download_fp);
rewind(CC->download_fp);
|| (!IsEmptyStr(cbid) && (!strcasecmp(CC->download_desired_section, cbid)))
) {
*found_it = 1;
- cprintf("%d %d\n", BINARY_FOLLOWS, (int)length);
+ cprintf("%d %d|-1|%s|%s|%s\n",
+ BINARY_FOLLOWS,
+ (int)length,
+ filename,
+ cbtype,
+ cbcharset
+ );
client_write(content, length);
}
}
+
+
+int CtdlDoIHavePermissionToReadMessagesInThisRoom(void) {
+ if ((!(CC->logged_in)) && (!(CC->internal_pgm))) {
+ return(om_not_logged_in);
+ }
+ return(om_ok);
+}
+
+
/*
* Get a message off disk. (returns om_* values found in msgbase.h)
*
int do_proto, /* do Citadel protocol responses? */
int crlf, /* Use CRLF newlines instead of LF? */
char *section, /* NULL or a message/rfc822 section */
- int flags /* should the bessage be exported clean? */
+ int flags /* various flags; see msgbase.h */
) {
struct CtdlMessage *TheMessage = NULL;
int retcode = om_no_such_msg;
struct encapmsg encap;
+ int r;
- CtdlLogPrintf(CTDL_DEBUG, "CtdlOutputMsg() msgnum=%ld, mode=%d, section=%s\n",
+ CtdlLogPrintf(CTDL_DEBUG, "CtdlOutputMsg(msgnum=%ld, mode=%d, section=%s)\n",
msg_num, mode,
(section ? section : "<>")
);
- if ((!(CC->logged_in)) && (!(CC->internal_pgm))) {
- if (do_proto) cprintf("%d Not logged in.\n",
- ERROR + NOT_LOGGED_IN);
- return(om_not_logged_in);
+ r = CtdlDoIHavePermissionToReadMessagesInThisRoom();
+ if (r != om_ok) {
+ if (do_proto) {
+ if (r == om_not_logged_in) {
+ cprintf("%d Not logged in.\n", ERROR + NOT_LOGGED_IN);
+ }
+ else {
+ cprintf("%d An unknown error has occurred.\n", ERROR);
+ }
+ }
+ return(r);
}
/* FIXME: check message id against msglist for this room */
}
+/* If the last item in a list of recipients was truncated to a partial address,
+ * remove it completely in order to avoid choking libSieve
+ */
+void sanitize_truncated_recipient(char *str)
+{
+ if (!str) return;
+ if (num_tokens(str, ',') < 2) return;
+
+ int len = strlen(str);
+ if (len < 900) return;
+ if (len > 998) str[998] = 0;
+
+ char *cptr = strrchr(str, ',');
+ if (!cptr) return;
+
+ char *lptr = strchr(cptr, '<');
+ char *rptr = strchr(cptr, '>');
+
+ if ( (lptr) && (rptr) && (rptr > lptr) ) return;
+
+ *cptr = 0;
+}
+
+
+
/*
* Get a message off disk. (returns om_* values found in msgbase.h)
*/
char allkeys[30];
char display_name[256];
char *mptr, *mpptr;
- char *nl; /* newline string */
+ const char *nl; /* newline string */
int suppress_f = 0;
int subject_found = 0;
struct ma_info ma;
return(om_no_such_msg);
}
+ /* Suppress envelope recipients if required to avoid disclosing BCC addresses.
+ * Pad it with spaces in order to avoid changing the RFC822 length of the message.
+ */
+ if ( (flags & SUPPRESS_ENV_TO) && (TheMessage->cm_fields['V'] != NULL) ) {
+ memset(TheMessage->cm_fields['V'], ' ', strlen(TheMessage->cm_fields['V']));
+ }
+
/* Are we downloading a MIME component? */
if (mode == MT_DOWNLOAD) {
if (TheMessage->cm_format_type != FMT_RFC822) {
/* nhdr=yes means that we're only displaying headers, no body */
if ( (TheMessage->cm_anon_type == MES_ANONONLY)
- && (mode == MT_CITADEL)
+ && ((mode == MT_CITADEL) || (mode == MT_MIME))
&& (do_proto)
) {
cprintf("nhdr=yes\n");
if (haschar(TheMessage->cm_fields['N'], '.') == 0) {
suppress_f = 1;
}
-
+
/* Now spew the header fields in the order we like them. */
safestrncpy(allkeys, FORDER, sizeof allkeys);
for (i=0; i<strlen(allkeys); ++i) {
if (k != 'M') {
if ( (TheMessage->cm_fields[k] != NULL)
&& (msgkeys[k] != NULL) ) {
+ if ((k == 'V') || (k == 'R') || (k == 'Y')) {
+ sanitize_truncated_recipient(TheMessage->cm_fields[k]);
+ }
if (k == 'A') {
if (do_proto) cprintf("%s=%s\n",
msgkeys[k],
safestrncpy(suser, mptr, sizeof suser);
}
else if (i == 'Y') {
- if ((flags & QP_EADDR) != 0)
+ if ((flags & QP_EADDR) != 0) {
mptr = qp_encode_email_addrs(mptr);
- fold_cprintf("CC: %s%s", mptr, nl);
+ }
+ sanitize_truncated_recipient(mptr);
+ cprintf("CC: %s%s", mptr, nl);
}
else if (i == 'P') {
cprintf("Return-Path: %s%s", mptr, nl);
{
if (haschar(mptr, '@') == 0)
{
- fold_cprintf("To: %s@%s%s", mptr, config.c_fqdn, nl);
+ sanitize_truncated_recipient(mptr);
+ cprintf("To: %s@%s", mptr, config.c_fqdn);
+ cprintf("%s", nl);
}
else
{
- if ((flags & QP_EADDR) != 0)
+ if ((flags & QP_EADDR) != 0) {
mptr = qp_encode_email_addrs(mptr);
- fold_cprintf("To: %s%s", mptr, nl);
+ }
+ sanitize_truncated_recipient(mptr);
+ cprintf("To: %s", mptr);
+ cprintf("%s", nl);
}
}
else if (i == 'T') {
(void *)&ma, 0);
}
else if (mode == MT_RFC822) { /* unparsed RFC822 dump */
- char *start_of_text = NULL;
- start_of_text = strstr(mptr, "\n\r\n");
- if (start_of_text == NULL) start_of_text = strstr(mptr, "\n\n");
- if (start_of_text == NULL) start_of_text = mptr;
- ++start_of_text;
- start_of_text = strstr(start_of_text, "\n");
- ++start_of_text;
+ int eoh = 0;
char outbuf[1024];
int outlen = 0;
int nllen = strlen(nl);
prev_ch = 0;
- while (ch=*mptr, ch!=0) {
- if (ch==13) {
+ while (*mptr != '\0') {
+ if (*mptr == '\r') {
/* do nothing */
}
else {
+ if ((!eoh) &&
+ (*mptr == '\n'))
+ {
+ eoh = (*(mptr+1) == '\r') && (*(mptr+2) == '\n');
+ if (!eoh)
+ eoh = *(mptr+1) == '\n';
+ }
+
if (
- ((headers_only == HEADERS_NONE) && (mptr >= start_of_text))
- || ((headers_only == HEADERS_ONLY) && (mptr < start_of_text))
+ ((headers_only == HEADERS_NONE) && (eoh))
+ || ((headers_only == HEADERS_ONLY) && (!eoh))
|| ((headers_only != HEADERS_NONE) && (headers_only != HEADERS_ONLY))
) {
- if (ch == 10) {
- sprintf(&outbuf[outlen], "%s", nl);
+ if (*mptr == '\n') {
+ memcpy(&outbuf[outlen], nl, nllen);
outlen += nllen;
+ outbuf[outlen] = '\0';
}
else {
- outbuf[outlen++] = ch;
+ outbuf[outlen++] = *mptr;
}
}
}
if (flags & ESC_DOT)
{
- if ((prev_ch == 10) && (ch == '.') && ((*(mptr+1) == 13) || (*(mptr+1) == 10)))
+ if ((prev_ch == '\n') && (*mptr == '.') && ((*(mptr+1) == '\r') || (*(mptr+1) == '\n')))
{
outbuf[outlen++] = '.';
}
}
- prev_ch = ch;
+ prev_ch = *mptr;
++mptr;
if (outlen > 1000) {
client_write(outbuf, outlen);
*/
if (TheMessage->cm_format_type == FMT_FIXED) {
int buflen;
+ int xlline = 0;
+ int nllen = strlen (nl);
if (mode == MT_MIME) {
cprintf("Content-type: text/plain\n\n");
}
*buf = '\0';
buflen = 0;
while (ch = *mptr++, ch > 0) {
- if (ch == 13)
- ch = 10;
- if ((ch == 10) || (buflen > 250)) {
+ if (ch == '\n')
+ ch = '\r';
+
+ if ((buflen > 250) && (!xlline)){
+ int tbuflen;
+ tbuflen = buflen;
+
+ while ((buflen > 0) &&
+ (!isspace(buf[buflen])))
+ buflen --;
+ if (buflen == 0) {
+ xlline = 1;
+ }
+ else {
+ mptr -= tbuflen - buflen;
+ buf[buflen] = '\0';
+ ch = '\r';
+ }
+ }
+ /* if we reach the outer bounds of our buffer,
+ abort without respect what whe purge. */
+ if (xlline &&
+ ((isspace(ch)) ||
+ (buflen > SIZ - nllen - 2)))
+ ch = '\r';
+
+ if (ch == '\r') {
+ memcpy (&buf[buflen], nl, nllen);
+ buflen += nllen;
buf[buflen] = '\0';
- cprintf("%s%s", buf, nl);
+
+ client_write(buf, buflen);
*buf = '\0';
buflen = 0;
+ xlline = 0;
} else {
buf[buflen] = ch;
buflen++;
if (mode == MT_MIME) {
cprintf("Content-type: text/x-citadel-variformat\n\n");
}
- memfmout(mptr, 0, nl);
+ memfmout(mptr, nl);
}
/* If the message on disk is format 4 (MIME), we've gotta hand it
* this mode of operation only works if we're saving a single message.)
*/
int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newmsgs,
- int do_repl_check, struct CtdlMessage *supplied_msg)
-{
+ int do_repl_check, struct CtdlMessage *supplied_msg, int suppress_refcount_adj
+) {
int i, j, unique;
char hold_rm[ROOMNAMELEN];
struct cdbdata *cdbfr;
int num_msgs_to_be_merged = 0;
CtdlLogPrintf(CTDL_DEBUG,
- "CtdlSaveMsgPointersInRoom(room=%s, num_msgs=%d, repl=%d)\n",
- roomname, num_newmsgs, do_repl_check);
+ "CtdlSaveMsgPointersInRoom(room=%s, num_msgs=%d, repl=%d, suppress_rca=%d)\n",
+ roomname, num_newmsgs, do_repl_check, suppress_refcount_adj
+ );
strcpy(hold_rm, CC->room.QRname);
if (num_newmsgs > 1) supplied_msg = NULL;
/* Now the regular stuff */
- if (lgetroom(&CC->room,
+ if (CtdlGetRoomLock(&CC->room,
((roomname != NULL) ? roomname : CC->room.QRname) )
!= 0) {
CtdlLogPrintf(CTDL_ERR, "No such room <%s>\n", roomname);
/* Update the highest-message pointer and unlock the room. */
CC->room.QRhighest = highest_msg;
- lputroom(&CC->room);
+ CtdlPutRoomLock(&CC->room);
/* Perform replication checks if necessary */
if ( (DoesThisRoomNeedEuidIndexing(&CC->room)) && (do_repl_check) ) {
PerformRoomHooks(&CC->room);
/* Go back to the room we were in before we wandered here... */
- getroom(&CC->room, hold_rm);
+ CtdlGetRoom(&CC->room, hold_rm);
/* Bump the reference count for all messages which were merged */
- for (i=0; i<num_msgs_to_be_merged; ++i) {
- AdjRefCount(msgs_to_be_merged[i], +1);
+ if (!suppress_refcount_adj) {
+ for (i=0; i<num_msgs_to_be_merged; ++i) {
+ AdjRefCount(msgs_to_be_merged[i], +1);
+ }
}
/* Free up memory... */
int CtdlSaveMsgPointerInRoom(char *roomname, long msgid,
int do_repl_check, struct CtdlMessage *supplied_msg)
{
- return CtdlSaveMsgPointersInRoom(roomname, &msgid, 1, do_repl_check, supplied_msg);
+ return CtdlSaveMsgPointersInRoom(roomname, &msgid, 1, do_repl_check, supplied_msg, 0);
}
/*CtdlLogPrintf(CTDL_DEBUG, "Exclusive ID: <%s> for room <%s>\n",
msg->cm_fields['E'], CC->room.QRname);*/
- old_msgnum = locate_message_by_euid(msg->cm_fields['E'], &CC->room);
+ old_msgnum = CtdlLocateMessageByEuid(msg->cm_fields['E'], &CC->room);
if (old_msgnum > 0L) {
CtdlLogPrintf(CTDL_DEBUG, "ReplicationChecks() replacing message %ld\n", old_msgnum);
CtdlDeleteMessages(CC->room.QRname, &old_msgnum, 1, "");
long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */
struct recptypes *recps, /* recipients (if mail) */
char *force, /* force a particular room? */
- int flags /* should the bessage be exported clean? */
+ int flags /* should the message be exported clean? */
) {
char submit_filename[128];
char generated_timestamp[32];
char content_type[SIZ]; /* We have to learn this */
char recipient[SIZ];
long newmsgid;
- char *mptr = NULL;
+ const char *mptr = NULL;
struct ctdluser userbuf;
int a, i;
struct MetaData smi;
struct addresses_to_be_filed *aptr = NULL;
char *saved_rfc822_version = NULL;
int qualified_for_journaling = 0;
- struct CitContext *CCC = CC; /* CachedCitContext - performance boost */
+ CitContext *CCC = CC; /* CachedCitContext - performance boost */
char bounce_to[1024] = "";
+ size_t tmp = 0;
+ int rv = 0;
CtdlLogPrintf(CTDL_DEBUG, "CtdlSubmitMsg() called\n");
if (is_valid_message(msg) == 0) return(-1); /* self check */
/* If the user is a twit, move to the twit room for posting */
if (TWITDETECT) {
- if (CCC->user.axlevel == 2) {
+ if (CCC->user.axlevel == AxProbU) {
strcpy(hold_rm, actual_rm);
strcpy(actual_rm, config.c_twitroom);
CtdlLogPrintf(CTDL_DEBUG, "Diverting to twit room\n");
CtdlLogPrintf(CTDL_DEBUG, "Final selection: %s\n", actual_rm);
if (strcasecmp(actual_rm, CCC->room.QRname)) {
- /* getroom(&CCC->room, actual_rm); */
- usergoto(actual_rm, 0, 1, NULL, NULL);
+ /* CtdlGetRoom(&CCC->room, actual_rm); */
+ CtdlUserGoto(actual_rm, 0, 1, NULL, NULL);
}
/*
}
/* For internet mail, drop a copy in the outbound queue room */
- if (recps != NULL)
- if (recps->num_internet > 0) {
+ if ((recps != NULL) && (recps->num_internet > 0)) {
CtdlSaveMsgPointerInRoom(SMTP_SPOOLOUT_ROOM, newmsgid, 0, msg);
}
/* If other rooms are specified, drop them there too. */
- if (recps != NULL)
- if (recps->num_room > 0)
+ if ((recps != NULL) && (recps->num_room > 0))
for (i=0; i<num_tokens(recps->recp_room, '|'); ++i) {
extract_token(recipient, recps->recp_room, i,
'|', sizeof recipient);
/* Bump this user's messages posted counter. */
CtdlLogPrintf(CTDL_DEBUG, "Updating user\n");
- lgetuser(&CCC->user, CCC->curr_user);
+ CtdlGetUserLock(&CCC->user, CCC->curr_user);
CCC->user.posted = CCC->user.posted + 1;
- lputuser(&CCC->user);
+ CtdlPutUserLock(&CCC->user);
/* Decide where bounces need to be delivered */
- if (CCC->logged_in) {
+ if ((recps != NULL) && (recps->bounce_to != NULL)) {
+ safestrncpy(bounce_to, recps->bounce_to, sizeof bounce_to);
+ }
+ else if (CCC->logged_in) {
snprintf(bounce_to, sizeof bounce_to, "%s@%s", CCC->user.fullname, config.c_nodename);
}
else {
/* If this is private, local mail, make a copy in the
* recipient's mailbox and bump the reference count.
*/
- if (recps != NULL)
- if (recps->num_local > 0)
+ if ((recps != NULL) && (recps->num_local > 0))
for (i=0; i<num_tokens(recps->recp_local, '|'); ++i) {
extract_token(recipient, recps->recp_local, i,
'|', sizeof recipient);
CtdlLogPrintf(CTDL_DEBUG, "Delivering private local mail to <%s>\n",
recipient);
- if (getuser(&userbuf, recipient) == 0) {
+ if (CtdlGetUser(&userbuf, recipient) == 0) {
// Add a flag so the Funambol module knows its mail
msg->cm_fields['W'] = strdup(recipient);
- MailboxName(actual_rm, sizeof actual_rm, &userbuf, MAILROOM);
+ CtdlMailboxName(actual_rm, sizeof actual_rm, &userbuf, MAILROOM);
CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 0, msg);
- BumpNewMailCounter(userbuf.usernum);
+ CtdlBumpNewMailCounter(userbuf.usernum);
if (!IsEmptyStr(config.c_funambol_host) || !IsEmptyStr(config.c_pager_program)) {
/* Generate a instruction message for the Funambol notification
* server, in the same style as the SMTP queue
* node. We'll revisit this again in a year or so when everyone has
* a network spool receiver that can handle the new style messages.
*/
- if (recps != NULL)
- if (recps->num_ignet > 0)
+ if ((recps != NULL) && (recps->num_ignet > 0))
for (i=0; i<num_tokens(recps->recp_ignet, '|'); ++i) {
extract_token(recipient, recps->recp_ignet, i,
'|', sizeof recipient);
(long) getpid(), CCC->cs_pid, ++seqnum);
network_fp = fopen(submit_filename, "wb+");
if (network_fp != NULL) {
- fwrite(smr.ser, smr.len, 1, network_fp);
+ rv = fwrite(smr.ser, smr.len, 1, network_fp);
fclose(network_fp);
}
free(smr.ser);
/* Go back to the room we started from */
CtdlLogPrintf(CTDL_DEBUG, "Returning to original room %s\n", hold_rm);
if (strcasecmp(hold_rm, CCC->room.QRname))
- usergoto(hold_rm, 0, 1, NULL, NULL);
+ CtdlUserGoto(hold_rm, 0, 1, NULL, NULL);
/* For internet mail, generate delivery instructions.
* Yes, this is recursive. Deal with it. Infinite recursion does
* not happen because the delivery instructions message does not
* contain a recipient.
*/
- if (recps != NULL)
- if (recps->num_internet > 0) {
+ if ((recps != NULL) && (recps->num_internet > 0)) {
CtdlLogPrintf(CTDL_DEBUG, "Generating delivery instructions\n");
instr_alloc = 1024;
instr = malloc(instr_alloc);
bounce_to
);
+ if (recps->envelope_from != NULL) {
+ tmp = strlen(instr);
+ snprintf(&instr[tmp], instr_alloc-tmp, "envelope_from|%s\n", recps->envelope_from);
+ }
+
for (i=0; i<num_tokens(recps->recp_internet, '|'); ++i) {
- size_t tmp = strlen(instr);
+ tmp = strlen(instr);
extract_token(recipient, recps->recp_internet, i, '|', sizeof recipient);
if ((tmp + strlen(recipient) + 32) > instr_alloc) {
instr_alloc = instr_alloc * 2;
if (collected_addresses != NULL) {
aptr = (struct addresses_to_be_filed *)
malloc(sizeof(struct addresses_to_be_filed));
- MailboxName(actual_rm, sizeof actual_rm,
+ CtdlMailboxName(actual_rm, sizeof actual_rm,
&CCC->user, USERCONTACTSROOM);
aptr->roomname = strdup(actual_rm);
aptr->collected_addresses = collected_addresses;
+void aide_message (char *text, char *subject)
+{
+ quickie_message("Citadel",NULL,NULL,AIDEROOM,text,FMT_CITADEL,subject);
+}
/*
* Convenience function for generating small administrative messages.
*/
-void quickie_message(char *from, char *fromaddr, char *to, char *room, char *text,
- int format_type, char *subject)
+void quickie_message(const char *from, const char *fromaddr, char *to, char *room, const char *text,
+ int format_type, const char *subject)
{
struct CtdlMessage *msg;
struct recptypes *recp = NULL;
/*
* Back end function used by CtdlMakeMessage() and similar functions
*/
-char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */
- size_t maxlen, /* maximum message length */
- char *exist, /* if non-null, append to it;
- exist is ALWAYS freed */
- int crlf, /* CRLF newlines instead of LF */
- int sock /* socket handle or 0 for this session's client socket */
- ) {
- char buf[1024];
- int linelen;
- size_t message_len = 0;
- size_t buffer_len = 0;
- char *ptr;
- char *m;
+StrBuf *CtdlReadMessageBodyBuf(char *terminator, /* token signalling EOT */
+ long tlen,
+ size_t maxlen, /* maximum message length */
+ char *exist, /* if non-null, append to it;
+ exist is ALWAYS freed */
+ int crlf, /* CRLF newlines instead of LF */
+ int *sock /* socket handle or 0 for this session's client socket */
+ )
+{
+ StrBuf *Message;
+ StrBuf *LineBuf;
int flushing = 0;
int finished = 0;
int dotdot = 0;
+ LineBuf = NewStrBufPlain(NULL, SIZ);
if (exist == NULL) {
- m = malloc(4096);
- m[0] = 0;
- buffer_len = 4096;
- message_len = 0;
+ Message = NewStrBufPlain(NULL, 4 * SIZ);
}
else {
- message_len = strlen(exist);
- buffer_len = message_len + 4096;
- m = realloc(exist, buffer_len);
- if (m == NULL) {
- free(exist);
- return m;
- }
+ Message = NewStrBufPlain(exist, -1);
+ free(exist);
}
/* Do we need to change leading ".." to "." for SMTP escaping? */
- if (!strcmp(terminator, ".")) {
+ if ((tlen == 1) && (*terminator == '.')) {
dotdot = 1;
}
- /* flush the input if we have nowhere to store it */
- if (m == NULL) {
- flushing = 1;
- }
-
/* read in the lines of message text one by one */
do {
- if (sock > 0) {
- if (sock_getln(sock, buf, (sizeof buf - 3)) < 0) finished = 1;
- }
- else {
- if (client_getln(buf, (sizeof buf - 3)) < 1) finished = 1;
- }
- if (!strcmp(buf, terminator)) finished = 1;
- if (crlf) {
- strcat(buf, "\r\n");
+ if (sock != NULL) {
+ if ((CtdlSockGetLine(sock, LineBuf) < 0) ||
+ (*sock == -1))
+ finished = 1;
}
else {
- strcat(buf, "\n");
- }
-
- /* Unescape SMTP-style input of two dots at the beginning of the line */
- if (dotdot) {
- if (!strncmp(buf, "..", 2)) {
- strcpy(buf, &buf[1]);
- }
+ if (CtdlClientGetLine(LineBuf) < 0) finished = 1;
}
+ if ((StrLength(LineBuf) == tlen) &&
+ (!strcmp(ChrPtr(LineBuf), terminator)))
+ finished = 1;
if ( (!flushing) && (!finished) ) {
- /* Measure the line */
- linelen = strlen(buf);
-
- /* augment the buffer if we have to */
- if ((message_len + linelen) >= buffer_len) {
- ptr = realloc(m, (buffer_len * 2) );
- if (ptr == NULL) { /* flush if can't allocate */
- flushing = 1;
- } else {
- buffer_len = (buffer_len * 2);
- m = ptr;
- CtdlLogPrintf(CTDL_DEBUG, "buffer_len is now %ld\n", (long)buffer_len);
- }
+ if (crlf) {
+ StrBufAppendBufPlain(LineBuf, HKEY("\r\n"), 0);
}
-
- /* Add the new line to the buffer. NOTE: this loop must avoid
- * using functions like strcat() and strlen() because they
- * traverse the entire buffer upon every call, and doing that
- * for a multi-megabyte message slows it down beyond usability.
- */
- strcpy(&m[message_len], buf);
- message_len += linelen;
+ else {
+ StrBufAppendBufPlain(LineBuf, HKEY("\n"), 0);
+ }
+
+ /* Unescape SMTP-style input of two dots at the beginning of the line */
+ if ((dotdot) &&
+ (StrLength(LineBuf) == 2) &&
+ (!strcmp(ChrPtr(LineBuf), "..")))
+ {
+ StrBufCutLeft(LineBuf, 1);
+ }
+
+ StrBufAppendBuf(Message, LineBuf, 0);
}
/* if we've hit the max msg length, flush the rest */
- if (message_len >= maxlen) flushing = 1;
+ if (StrLength(Message) >= maxlen) flushing = 1;
} while (!finished);
- return(m);
+ FreeStrBuf(&LineBuf);
+ return Message;
}
+/*
+ * Back end function used by CtdlMakeMessage() and similar functions
+ */
+char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */
+ long tlen,
+ size_t maxlen, /* maximum message length */
+ char *exist, /* if non-null, append to it;
+ exist is ALWAYS freed */
+ int crlf, /* CRLF newlines instead of LF */
+ int *sock /* socket handle or 0 for this session's client socket */
+ )
+{
+ StrBuf *Message;
+
+ Message = CtdlReadMessageBodyBuf(terminator,
+ tlen,
+ maxlen,
+ exist,
+ crlf,
+ sock);
+ if (Message == NULL)
+ return NULL;
+ else
+ return SmashStrBuf(&Message);
+}
/*
/* Don't confuse the poor folks if it's not routed mail. */
strcpy(dest_node, "");
- striplt(recipient);
- striplt(recp_cc);
+ if (recipient != NULL) striplt(recipient);
+ if (recp_cc != NULL) striplt(recp_cc);
/* Path or Return-Path */
if (my_email == NULL) my_email = "";
snprintf(buf, sizeof buf, "%ld", (long)time(NULL)); /* timestamp */
msg->cm_fields['T'] = strdup(buf);
- if (fake_name[0]) /* author */
+ if ((fake_name != NULL) && (fake_name[0])) { /* author */
msg->cm_fields['A'] = strdup(fake_name);
- else
+ }
+ else {
msg->cm_fields['A'] = strdup(author->fullname);
+ }
if (CC->room.QRflags & QR_MAILBOX) { /* room */
msg->cm_fields['O'] = strdup(&CC->room.QRname[11]);
msg->cm_fields['N'] = strdup(NODENAME); /* nodename */
msg->cm_fields['H'] = strdup(HUMANNODE); /* hnodename */
- if (recipient[0] != 0) {
+ if ((recipient != NULL) && (recipient[0] != 0)) {
msg->cm_fields['R'] = strdup(recipient);
}
- if (recp_cc[0] != 0) {
+ if ((recp_cc != NULL) && (recp_cc[0] != 0)) {
msg->cm_fields['Y'] = strdup(recp_cc);
}
if (dest_node[0] != 0) {
msg->cm_fields['M'] = preformatted_text;
}
else {
- msg->cm_fields['M'] = CtdlReadMessageBody("000", config.c_maxmsglen, NULL, 0, 0);
+ msg->cm_fields['M'] = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0);
}
return(msg);
}
- if ((CC->user.axlevel < 2)
+ if ((CC->user.axlevel < AxProbU)
&& ((CC->room.QRflags & QR_MAILBOX) == 0)) {
snprintf(errmsgbuf, n, "Need to be validated to enter "
"(except in %s> to sysop)", MAILROOM);
int CtdlCheckInternetMailPermission(struct ctdluser *who) {
/* Do not allow twits to send Internet mail */
- if (who->axlevel <= 2) return(0);
+ if (who->axlevel <= AxProbU) return(0);
/* Globally enabled? */
if (config.c_restrict == 0) return(1);
if (who->flags & US_INTERNET) return(2);
/* Aide level access? */
- if (who->axlevel >= 6) return(3);
+ if (who->axlevel >= AxAideU) return(3);
/* No mail for you! */
return(0);
*
* Caller needs to free the result using free_recipients()
*/
-struct recptypes *validate_recipients(char *supplied_recipients,
+struct recptypes *validate_recipients(const char *supplied_recipients,
const char *RemoteIdentifier,
int Flags) {
struct recptypes *ret;
strcat(ret->recp_room, this_recp);
}
else if ( (!strncasecmp(this_recp, "room_", 5))
- && (!getroom(&tempQR, &this_recp_cooked[5])) ) {
+ && (!CtdlGetRoom(&tempQR, &this_recp_cooked[5])) ) {
/* Save room so we can restore it later */
tempQR2 = CC->room;
CC->room = tempQR2;
}
- else if (getuser(&tempUS, this_recp) == 0) {
+ else if (CtdlGetUser(&tempUS, this_recp) == 0) {
++ret->num_local;
strcpy(this_recp, tempUS.fullname);
if (!IsEmptyStr(ret->recp_local)) {
}
strcat(ret->recp_local, this_recp);
}
- else if (getuser(&tempUS, this_recp_cooked) == 0) {
+ else if (CtdlGetUser(&tempUS, this_recp_cooked) == 0) {
++ret->num_local;
strcpy(this_recp, tempUS.fullname);
if (!IsEmptyStr(ret->recp_local)) {
if (valid->recp_ignet != NULL) free(valid->recp_ignet);
if (valid->recp_room != NULL) free(valid->recp_room);
if (valid->display_recp != NULL) free(valid->display_recp);
+ if (valid->bounce_to != NULL) free(valid->bounce_to);
+ if (valid->envelope_from != NULL) free(valid->envelope_from);
free(valid);
}
if (IsEmptyStr(newusername)) {
strcpy(newusername, CC->user.fullname);
}
- if ( (CC->user.axlevel < 6)
+ if ( (CC->user.axlevel < AxAideU)
&& (strcasecmp(newusername, CC->user.fullname))
&& (strcasecmp(newusername, CC->cs_inet_fn))
) {
if ( ( (CC->room.QRflags & QR_MAILBOX) && (!strcasecmp(&CC->room.QRname[11], MAILROOM)) )
|| ( (CC->room.QRflags & QR_MAILBOX) && (CC->curr_view == VIEW_MAILBOX) )
) {
- if (CC->user.axlevel < 2) {
+ if (CC->user.axlevel < AxProbU) {
strcpy(recp, "sysop");
strcpy(cc, "");
strcpy(bcc, "");
}
if ( ( (valid_to->num_internet + valid_to->num_ignet + valid_cc->num_internet + valid_cc->num_ignet + valid_bcc->num_internet + valid_bcc->num_ignet) > 0)
- && (CC->user.axlevel < 4) ) {
+ && (CC->user.axlevel < AxNetU) ) {
cprintf("%d Higher access required for network mail.\n",
ERROR + HIGHER_ACCESS_REQUIRED);
free_recipients(valid_to);
room_name, num_dmsgnums, content_type);
/* get room record, obtaining a lock... */
- if (lgetroom(&qrbuf, room_name) != 0) {
+ if (CtdlGetRoomLock(&qrbuf, room_name) != 0) {
CtdlLogPrintf(CTDL_ERR, "CtdlDeleteMessages(): Room <%s> not found\n",
room_name);
if (need_to_free_re) regfree(&re);
cdb_store(CDB_MSGLISTS, &qrbuf.QRnumber, (int)sizeof(long),
msglist, (int)(num_msgs * sizeof(long)));
- qrbuf.QRhighest = msglist[num_msgs - 1];
+ if (num_msgs > 0)
+ qrbuf.QRhighest = msglist[num_msgs - 1];
+ else
+ qrbuf.QRhighest = 0;
}
- lputroom(&qrbuf);
+ CtdlPutRoomLock(&qrbuf);
/* Go through the messages we pulled out of the index, and decrement
* their reference counts by 1. If this is the only room the message
}
-/*
- * Back end API function for moves and deletes (multiple messages)
- */
-int CtdlCopyMsgsToRoom(long *msgnums, int num_msgs, char *dest) {
- int err;
-
- err = CtdlSaveMsgPointersInRoom(dest, msgnums, num_msgs, 1, NULL);
- if (err != 0) return(err);
-
- return(0);
-}
-
-
/*
targ[ROOMNAMELEN - 1] = 0;
is_copy = extract_int(args, 2);
- if (getroom(&qtemp, targ) != 0) {
- cprintf("%d '%s' does not exist.\n",
- ERROR + ROOM_NOT_FOUND, targ);
+ if (CtdlGetRoom(&qtemp, targ) != 0) {
+ cprintf("%d '%s' does not exist.\n", ERROR + ROOM_NOT_FOUND, targ);
return;
}
- getuser(&CC->user, CC->curr_user);
+ if (!strcasecmp(qtemp.QRname, CC->room.QRname)) {
+ cprintf("%d Source and target rooms are the same.\n", ERROR + ALREADY_EXISTS);
+ return;
+ }
+
+ CtdlGetUser(&CC->user, CC->curr_user);
CtdlRoomAccess(&qtemp, &CC->user, &ra, NULL);
/* Check for permission to perform this operation.
permit = 0;
/* Aides can move/copy */
- if (CC->user.axlevel >= 6) permit = 1;
+ if (CC->user.axlevel >= AxAideU) permit = 1;
/* Room aides can move/copy */
if (CC->user.usernum == CC->room.QRroomaide) permit = 1;
/*
* Do the copy
*/
- err = CtdlCopyMsgsToRoom(msgs, num_msgs, targ);
+ err = CtdlSaveMsgPointersInRoom(targ, msgs, num_msgs, 1, NULL, 0);
if (err != 0) {
cprintf("%d Cannot store message(s) in %s: error %d\n",
err, targ, err);
void AdjRefCount(long msgnum, int incr)
{
struct arcq new_arcq;
+ int rv = 0;
+
+ CtdlLogPrintf(CTDL_DEBUG, "AdjRefCount() msg %ld ref count delta %+d\n",
+ msgnum, incr
+ );
begin_critical_section(S_SUPPMSGMAIN);
if (arcfp == NULL) {
new_arcq.arcq_msgnum = msgnum;
new_arcq.arcq_delta = incr;
- fwrite(&new_arcq, sizeof(struct arcq), 1, arcfp);
+ rv = fwrite(&new_arcq, sizeof(struct arcq), 1, arcfp);
fflush(arcfp);
return;
smi.meta_refcount += incr;
PutMetaData(&smi);
end_critical_section(S_SUPPMSGMAIN);
- CtdlLogPrintf(CTDL_DEBUG, "msg %ld ref count delta %+d, is now %d\n",
- msgnum, incr, smi.meta_refcount);
+ CtdlLogPrintf(CTDL_DEBUG, "TDAP_AdjRefCount() msg %ld ref count delta %+d, is now %d\n",
+ msgnum, incr, smi.meta_refcount
+ );
/* If the reference count is now zero, delete the message
* (and its supplementary record as well).
char *encoded_message = NULL;
if (is_mailbox != NULL) {
- MailboxName(roomname, sizeof roomname, is_mailbox, req_room);
+ CtdlMailboxName(roomname, sizeof roomname, is_mailbox, req_room);
}
else {
safestrncpy(roomname, req_room, sizeof(roomname));
msg->cm_fields['M'] = encoded_message;
/* Create the requested room if we have to. */
- if (getroom(&qrbuf, roomname) != 0) {
- create_room(roomname,
+ if (CtdlGetRoom(&qrbuf, roomname) != 0) {
+ CtdlCreateRoom(roomname,
( (is_mailbox != NULL) ? 5 : 3 ),
"", 0, 1, 0, VIEW_BBS);
}
char buf[SIZ];
strcpy(hold_rm, CC->room.QRname);
- if (getroom(&CC->room, SYSCONFIGROOM) != 0) {
- getroom(&CC->room, hold_rm);
+ if (CtdlGetRoom(&CC->room, SYSCONFIGROOM) != 0) {
+ CtdlGetRoom(&CC->room, hold_rm);
return NULL;
}
}
}
- getroom(&CC->room, hold_rm);
+ CtdlGetRoom(&CC->room, hold_rm);
if (conf != NULL) do {
extract_token(buf, conf, 0, '\n', sizeof buf);
}
}
+
+
+/*****************************************************************************/
+/* MODULE INITIALIZATION STUFF */
+/*****************************************************************************/
+
+CTDL_MODULE_INIT(msgbase)
+{
+ if (!threading) {
+ CtdlRegisterProtoHook(cmd_msgs, "MSGS", "Output a list of messages in the current room");
+ CtdlRegisterProtoHook(cmd_msg0, "MSG0", "Output a message in plain text format");
+ CtdlRegisterProtoHook(cmd_msg2, "MSG2", "Output a message in RFC822 format");
+ CtdlRegisterProtoHook(cmd_msg3, "MSG3", "Output a message in raw format (deprecated)");
+ CtdlRegisterProtoHook(cmd_msg4, "MSG4", "Output a message in the client's preferred format");
+ CtdlRegisterProtoHook(cmd_msgp, "MSGP", "Select preferred format for MSG4 output");
+ CtdlRegisterProtoHook(cmd_opna, "OPNA", "Open an attachment for download");
+ CtdlRegisterProtoHook(cmd_dlat, "DLAT", "Download an attachment");
+ CtdlRegisterProtoHook(cmd_ent0, "ENT0", "Enter a message");
+ CtdlRegisterProtoHook(cmd_dele, "DELE", "Delete a message");
+ CtdlRegisterProtoHook(cmd_move, "MOVE", "Move or copy a message to another room");
+ CtdlRegisterProtoHook(cmd_isme, "ISME", "Determine whether an email address belongs to a user");
+ }
+
+ /* return our Subversion id for the Log */
+ return "$Id$";
+}