X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmsgbase.c;h=98510111a8ff51f0d365914409b94594c236ad8a;hb=182f984f6f03067f40a7e01bfa82df95f5605358;hp=aac75e05319d9f0a69fb4c8939e0f04b6ae25ae1;hpb=c73d2ab04533468048b4cd6eacaca574151a9706;p=citadel.git diff --git a/citadel/msgbase.c b/citadel/msgbase.c index aac75e053..98510111a 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -2,22 +2,22 @@ * $Id$ * * Implements the message store. - * - * Copyright (c) 1987-2009 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. + * 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. + * 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 + * 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" @@ -927,79 +927,56 @@ void do_help_subst(char *buffer) */ 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; + } } @@ -1015,8 +992,15 @@ void list_this_part(char *name, char *filename, char *partnum, char *disp, 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); } } @@ -1104,11 +1088,12 @@ void mime_spew_section(char *name, char *filename, char *partnum, char *disp, || (!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); } @@ -1743,7 +1728,7 @@ int CtdlOutputPreLoadedMsg( 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; @@ -2063,45 +2048,48 @@ START_TEXT: (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); @@ -2132,19 +2120,49 @@ START_TEXT: */ 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++; @@ -2166,7 +2184,7 @@ START_TEXT: 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 @@ -2349,8 +2367,8 @@ void cmd_dlat(char *cmdbuf) * 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; @@ -2365,8 +2383,9 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms 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); @@ -2487,8 +2506,10 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms CtdlGetRoom(&CC->room, hold_rm); /* Bump the reference count for all messages which were merged */ - for (i=0; iuser.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"); @@ -3202,105 +3223,102 @@ void quickie_message(const char *from, const char *fromaddr, char *to, char *roo /* * 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; + if (sock != NULL) { + if ((CtdlSockGetLine(sock, LineBuf) < 0) || + (*sock == -1)) + 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); +} /* @@ -3426,7 +3444,7 @@ struct CtdlMessage *CtdlMakeMessage( 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); @@ -3498,7 +3516,7 @@ int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, } - 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); @@ -3523,7 +3541,7 @@ int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, 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); @@ -3532,7 +3550,7 @@ int CtdlCheckInternetMailPermission(struct ctdluser *who) { 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); @@ -3548,7 +3566,7 @@ int CtdlCheckInternetMailPermission(struct ctdluser *who) { * * 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; @@ -3884,7 +3902,7 @@ void cmd_ent0(char *entargs) 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)) ) { @@ -3934,7 +3952,7 @@ void cmd_ent0(char *entargs) 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, ""); @@ -3986,7 +4004,7 @@ void cmd_ent0(char *entargs) } 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); @@ -4204,7 +4222,10 @@ int CtdlDeleteMessages(char *room_name, /* which room */ 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); @@ -4342,7 +4363,7 @@ void cmd_move(char *args) 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; @@ -4384,7 +4405,7 @@ void cmd_move(char *args) /* * Do the copy */ - err = CtdlSaveMsgPointersInRoom(targ, msgs, num_msgs, 1, NULL); + 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); @@ -4458,6 +4479,10 @@ 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) { arcfp = fopen(file_arcq, "ab+"); @@ -4571,8 +4596,9 @@ void TDAP_AdjRefCount(long msgnum, int incr) 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).