* $Id$
*
* 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"
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.
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 */
+ const 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 */
-
+ StrBuf *OutBuf;
+ char *LineStart;
+ char *LastBlank;
+ size_t len;
+ size_t NLLen;
+ char *eptr;
+ int NLFound, NLFoundLastTime;
+ int Found;
+
+ len = strlen (mptr);
+ NLLen = strlen (nl);
+ eptr = mptr + len;
+
+ OutBuf = NewStrBufPlain(NULL, 200);
+
+ NLFound = NLFoundLastTime = 0;
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;
- }
- if (((old == 13) || (old == 10)) && (isspace(real))) {
- cprintf("%s", nl);
- c = 1;
- }
- 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;
+ size_t i;
+
+ LineStart = LastBlank = mptr;
+ Found = 'x';
+ i = 0;
+ while (Found == 'x')
+ {
+ if (LineStart[i] == '\n')
+ Found = '\n';
+ else if (LineStart[i] == '\r')
+ Found = '\r';
+ else if (LineStart[i] == ' ')
+ {
+ LastBlank = &LineStart[i];
+ i++;
}
- cprintf("%s ", aaa);
- ++c;
- c = c + strlen(aaa);
- strcpy(aaa, "");
+ else if ((i > 80) && (LineStart != LastBlank))
+ Found = ' ';
+ else if (LineStart[i] == '\0')
+ Found = '\0';
+ else i++;
}
- if ((ch == 13) || (ch == 10)) {
- cprintf("%s%s", aaa, nl);
- c = 1;
- strcpy(aaa, "");
+ switch (Found)
+ {
+ case '\n':
+ if (LineStart[i + 1] == '\r')
+ mptr = &LineStart[i + 2];
+ else
+ mptr = &LineStart[i + 1];
+ i--;
+ NLFound = 1;
+ break;
+ case '\r':
+ if (LineStart[i + 1] == '\n')
+ mptr = &LineStart[i + 2];
+ else
+ mptr = &LineStart[i + 1];
+ i--;
+ NLFound = 1;
+ break;
+ case '\0':
+ mptr = &LineStart[i + 1];
+ i--;
+ NLFound = 0;
+ break;
+ case ' ':
+ mptr = LastBlank + 1;
+ i = LastBlank - LineStart;
+ NLFound = 0;
+ break;
+ case 'x':
+ /* WHUT? */
+ while (*mptr != '\0') mptr++;
+ break;
}
-
- } while (ch > 0);
-
- cprintf("%s%s", aaa, nl);
+ if (NLFoundLastTime)
+ StrBufPlain(OutBuf, HKEY(" "));
+ else
+ FlushStrBuf(OutBuf);
+ StrBufAppendBufPlain(OutBuf, LineStart, i, 0);
+ StrBufAppendBufPlain(OutBuf, nl, NLLen, 0);
+
+ cputbuf(OutBuf);
+ NLFoundLastTime = NLFound;
+ } while (*mptr != '\0');
+
+ FreeStrBuf(&OutBuf);
}
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);
}
}
|| (!IsEmptyStr(cbid) && (!strcasecmp(CC->download_desired_section, cbid)))
) {
*found_it = 1;
- cprintf("%d %d|-1|%s|%s\n",
+ cprintf("%d %d|-1|%s|%s|%s\n",
BINARY_FOLLOWS,
(int)length,
filename,
- cbtype
+ cbtype,
+ cbcharset
);
client_write(content, length);
}
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;
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
/*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];
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;
/* 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 ((recps != NULL) && (recps->bounce_to != NULL)) {
'|', 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
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);
+}
/*
/*
* 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 */
- ) {
+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;
char buf[1024];
- int linelen;
- size_t message_len = 0;
- size_t buffer_len = 0;
- char *ptr;
- char *m;
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");
- }
- 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);
+}
/*
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);
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)) {
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;
}
CtdlPutRoomLock(&qrbuf);
return;
}
- getuser(&CC->user, CC->curr_user);
+ CtdlGetUser(&CC->user, CC->curr_user);
CtdlRoomAccess(&qtemp, &CC->user, &ra, NULL);
/* Check for permission to perform this operation.
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));
CTDL_MODULE_INIT(msgbase)
{
- 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");
+ 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$";