X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmsgbase.c;h=10ec60887d068f470c6e667aea2a166a9f33af69;hb=4bb58f061555ed9770803727c1408ede497deb32;hp=361f791a3e626776bbdaa6c95170da50028b36f8;hpb=f232d39a0676e3355f47524e7cd2cec907c1b5e8;p=citadel.git diff --git a/citadel/msgbase.c b/citadel/msgbase.c index 361f791a3..10ec60887 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "citadel.h" #include "server.h" #include "serv_extensions.h" @@ -44,16 +45,14 @@ #include "file_ops.h" #include "config.h" #include "control.h" -#include "tools.h" -#include "mime_parser.h" -#include "html.h" #include "genstamp.h" #include "internet_addressing.h" -#include "vcard.h" #include "euidindex.h" #include "journaling.h" #include "citadel_dirs.h" - +#include "clientsocket.h" +#include "serv_network.h" +#include "threads.h" long config_msgnum; struct addresses_to_be_filed *atbf = NULL; @@ -541,9 +540,7 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long)); if (cdbfr != NULL) { msglist = (long *) cdbfr->ptr; - cdbfr->ptr = NULL; /* CtdlForEachMessage() now owns this memory */ num_msgs = cdbfr->len / sizeof(long); - cdb_free(cdbfr); } else { if (need_to_free_re) regfree(&re); return 0; /* No messages at all? No further action. */ @@ -679,7 +676,7 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, ++num_processed; } } - free(msglist); /* Clean up */ + cdb_free(cdbfr); /* Clean up */ if (need_to_free_re) regfree(&re); return num_processed; } @@ -808,7 +805,7 @@ void do_help_subst(char *buffer) help_subst(buffer, "^variantname", CITADEL); snprintf(buf2, sizeof buf2, "%d", config.c_maxsessions); help_subst(buffer, "^maxsessions", buf2); - help_subst(buffer, "^bbsdir", ctdl_bbsbase_dir); + help_subst(buffer, "^bbsdir", ctdl_message_dir); } @@ -1035,9 +1032,7 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) */ ch = *mptr++; if (ch != 255) { - lprintf(CTDL_ERR, - "Message %ld appears to be corrupted.\n", - msgnum); + lprintf(CTDL_ERR, "Message %ld appears to be corrupted.\n", msgnum); cdb_free(dmsgtext); return NULL; } @@ -1200,8 +1195,7 @@ void fixed_output(char *name, char *filename, char *partnum, char *disp, * we've already printed another section, skip this one. */ if ( (ma->is_ma) && (ma->did_print) ) { - lprintf(CTDL_DEBUG, "Skipping part %s (%s)\n", - partnum, cbtype); + lprintf(CTDL_DEBUG, "Skipping part %s (%s)\n", partnum, cbtype); return; } ma->did_print = 1; @@ -1264,14 +1258,18 @@ void choose_preferred(char *name, char *filename, char *partnum, char *disp, ma = (struct ma_info *)cbuserdata; - if (ma->is_ma > 0) { - for (i=0; ipreferred_formats, '|'); ++i) { - extract_token(buf, CC->preferred_formats, i, '|', sizeof buf); - if ( (!strcasecmp(buf, cbtype)) && (!ma->freeze) ) { - if (i < ma->chosen_pref) { - safestrncpy(ma->chosen_part, partnum, sizeof ma->chosen_part); - ma->chosen_pref = i; - } + // NOTE: REMOVING THIS CONDITIONAL FIXES BUG 220 + // http://bugzilla.citadel.org/show_bug.cgi?id=220 + // I don't know if there are any side effects! Please TEST TEST TEST + //if (ma->is_ma > 0) { + + for (i=0; ipreferred_formats, '|'); ++i) { + extract_token(buf, CC->preferred_formats, i, '|', sizeof buf); + if ( (!strcasecmp(buf, cbtype)) && (!ma->freeze) ) { + if (i < ma->chosen_pref) { + lprintf(CTDL_DEBUG, "Setting chosen part: <%s>\n", partnum); + safestrncpy(ma->chosen_part, partnum, sizeof ma->chosen_part); + ma->chosen_pref = i; } } } @@ -1446,9 +1444,7 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ } /* Ok, output the message now */ - retcode = CtdlOutputPreLoadedMsg( - TheMessage, mode, - headers_only, do_proto, crlf); + retcode = CtdlOutputPreLoadedMsg(TheMessage, mode, headers_only, do_proto, crlf); CtdlFreeMessage(TheMessage); return(retcode); @@ -1457,7 +1453,6 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ /* * Get a message off disk. (returns om_* values found in msgbase.h) - * */ int CtdlOutputPreLoadedMsg( struct CtdlMessage *TheMessage, @@ -1712,7 +1707,7 @@ int CtdlOutputPreLoadedMsg( } /* Construct a fun message id */ - cprintf("Message-ID: <%s", mid); + cprintf("Message-ID: <%s", mid);/// todo: this possibly breaks threadding mails. if (strchr(mid, '@')==NULL) { cprintf("@%s", snode); } @@ -1814,21 +1809,26 @@ START_TEXT: * what message transfer format is in use. */ if (TheMessage->cm_format_type == FMT_FIXED) { + int buflen; if (mode == MT_MIME) { cprintf("Content-type: text/plain\n\n"); } - strcpy(buf, ""); + *buf = '\0'; + buflen = 0; while (ch = *mptr++, ch > 0) { if (ch == 13) ch = 10; - if ((ch == 10) || (strlen(buf) > 250)) { + if ((ch == 10) || (buflen > 250)) { + buf[buflen] = '\0'; cprintf("%s%s", buf, nl); - strcpy(buf, ""); + *buf = '\0'; + buflen = 0; } else { - buf[strlen(buf) + 1] = 0; - buf[strlen(buf)] = ch; + buf[buflen] = ch; + buflen++; } } + buf[buflen] = '\0'; if (!IsEmptyStr(buf)) cprintf("%s%s", buf, nl); } @@ -1863,7 +1863,7 @@ START_TEXT: *choose_preferred, *fixed_output_pre, *fixed_output_post, (void *)&ma, 0); mime_parser(mptr, NULL, - *output_preferred, NULL, NULL, (void *)&ma, 0); + *output_preferred, NULL, NULL, (void *)&ma, CC->msg4_dont_decode); } else { ma.use_fo_hooks = 1; @@ -1972,9 +1972,14 @@ void cmd_msg4(char *cmdbuf) */ void cmd_msgp(char *cmdbuf) { - safestrncpy(CC->preferred_formats, cmdbuf, - sizeof(CC->preferred_formats)); - cprintf("%d ok\n", CIT_OK); + if (!strcasecmp(cmdbuf, "dont_decode")) { + CC->msg4_dont_decode = 1; + cprintf("%d MSG4 will not pre-decode messages.\n", CIT_OK); + } + else { + safestrncpy(CC->preferred_formats, cmdbuf, sizeof(CC->preferred_formats)); + cprintf("%d Preferred MIME formats have been set.\n", CIT_OK); + } } @@ -2318,6 +2323,43 @@ void serialize_message(struct ser_ret *ret, /* return values */ } +/* + * Serialize a struct CtdlMessage into the format used on disk and network. + * + * This function loads up a "struct ser_ret" (defined in server.h) which + * contains the length of the serialized message and a pointer to the + * serialized message in memory. THE LATTER MUST BE FREED BY THE CALLER. + */ +void dump_message(struct CtdlMessage *msg, /* unserialized msg */ + long Siz) /* how many chars ? */ +{ + size_t wlen; + int i; + static char *forder = FORDER; + char *buf; + + /* + * Check for valid message format + */ + if (is_valid_message(msg) == 0) { + lprintf(CTDL_ERR, "dump_message() aborting due to invalid message\n"); + return; + } + + buf = (char*) malloc (Siz + 1); + + wlen = 3; + + for (i=0; i<26; ++i) if (msg->cm_fields[(int)forder[i]] != NULL) { + snprintf (buf, Siz, " msg[%c] = %s ...\n", (char) forder[i], + msg->cm_fields[(int)forder[i]]); + client_write (buf, strlen(buf)); + } + + return; +} + + /* * Check to see if any messages already exist in the current room which @@ -2377,6 +2419,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ struct addresses_to_be_filed *aptr = NULL; char *saved_rfc822_version = NULL; int qualified_for_journaling = 0; + struct CitContext *CCC = CC; /* CachedCitContext - performance boost */ lprintf(CTDL_DEBUG, "CtdlSubmitMsg() called\n"); if (is_valid_message(msg) == 0) return(-1); /* self check */ @@ -2429,30 +2472,33 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ strcpy(content_type, "text/plain"); mptr = bmstrcasestr(msg->cm_fields['M'], "Content-type:"); if (mptr != NULL) { + char *aptr; safestrncpy(content_type, &mptr[13], sizeof content_type); striplt(content_type); - for (a = 0; a < strlen(content_type); ++a) { - if ((content_type[a] == ';') - || (content_type[a] == ' ') - || (content_type[a] == 13) - || (content_type[a] == 10)) { - content_type[a] = 0; + aptr = content_type; + while (!IsEmptyStr(aptr)) { + if ((*aptr == ';') + || (*aptr == ' ') + || (*aptr == 13) + || (*aptr == 10)) { + *aptr = 0; } + else aptr++; } } } /* Goto the correct room */ - lprintf(CTDL_DEBUG, "Selected room %s\n", (recps) ? CC->room.QRname : SENTITEMS); - strcpy(hold_rm, CC->room.QRname); - strcpy(actual_rm, CC->room.QRname); + lprintf(CTDL_DEBUG, "Selected room %s\n", (recps) ? CCC->room.QRname : SENTITEMS); + strcpy(hold_rm, CCC->room.QRname); + strcpy(actual_rm, CCC->room.QRname); if (recps != NULL) { strcpy(actual_rm, SENTITEMS); } /* If the user is a twit, move to the twit room for posting */ if (TWITDETECT) { - if (CC->user.axlevel == 2) { + if (CCC->user.axlevel == 2) { strcpy(hold_rm, actual_rm); strcpy(actual_rm, config.c_twitroom); lprintf(CTDL_DEBUG, "Diverting to twit room\n"); @@ -2465,8 +2511,8 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } lprintf(CTDL_DEBUG, "Final selection: %s\n", actual_rm); - if (strcasecmp(actual_rm, CC->room.QRname)) { - /* getroom(&CC->room, actual_rm); */ + if (strcasecmp(actual_rm, CCC->room.QRname)) { + /* getroom(&CCC->room, actual_rm); */ usergoto(actual_rm, 0, 1, NULL, NULL); } @@ -2474,7 +2520,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * If this message has no O (room) field, generate one. */ if (msg->cm_fields['O'] == NULL) { - msg->cm_fields['O'] = strdup(CC->room.QRname); + msg->cm_fields['O'] = strdup(CCC->room.QRname); } /* Perform "before save" hooks (aborting if any return nonzero) */ @@ -2485,7 +2531,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * If this message has an Exclusive ID, and the room is replication * checking enabled, then do replication checks. */ - if (DoesThisRoomNeedEuidIndexing(&CC->room)) { + if (DoesThisRoomNeedEuidIndexing(&CCC->room)) { ReplicationChecks(msg); } @@ -2515,19 +2561,19 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * 2. If journaling is enabled, we will need an RFC822 version of the * message to attach to the journalized copy. */ - if (CC->redirect_buffer != NULL) { - lprintf(CTDL_ALERT, "CC->redirect_buffer is not NULL during message submission!\n"); + if (CCC->redirect_buffer != NULL) { + lprintf(CTDL_ALERT, "CCC->redirect_buffer is not NULL during message submission!\n"); abort(); } - CC->redirect_buffer = malloc(SIZ); - CC->redirect_len = 0; - CC->redirect_alloc = SIZ; + CCC->redirect_buffer = malloc(SIZ); + CCC->redirect_len = 0; + CCC->redirect_alloc = SIZ; CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1); - smi.meta_rfc822_length = CC->redirect_len; - saved_rfc822_version = CC->redirect_buffer; - CC->redirect_buffer = NULL; - CC->redirect_len = 0; - CC->redirect_alloc = 0; + smi.meta_rfc822_length = CCC->redirect_len; + saved_rfc822_version = CCC->redirect_buffer; + CCC->redirect_buffer = NULL; + CCC->redirect_len = 0; + CCC->redirect_alloc = 0; PutMetaData(&smi); @@ -2538,7 +2584,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ * 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) || (recps == NULL)) { + if ((!CCC->internal_pgm) || (recps == NULL)) { if (CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 1, msg) != 0) { lprintf(CTDL_ERR, "ERROR saving message pointer!\n"); CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg); @@ -2563,9 +2609,9 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* Bump this user's messages posted counter. */ lprintf(CTDL_DEBUG, "Updating user\n"); - lgetuser(&CC->user, CC->curr_user); - CC->user.posted = CC->user.posted + 1; - lputuser(&CC->user); + lgetuser(&CCC->user, CCC->curr_user); + CCC->user.posted = CCC->user.posted + 1; + lputuser(&CCC->user); /* If this is private, local mail, make a copy in the * recipient's mailbox and bump the reference count. @@ -2583,7 +2629,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ MailboxName(actual_rm, sizeof actual_rm, &userbuf, MAILROOM); CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 0, msg); BumpNewMailCounter(userbuf.usernum); - if (!IsEmptyStr(config.c_funambol_host)) { + 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 */ @@ -2646,7 +2692,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ snprintf(submit_filename, sizeof submit_filename, "%s/netmail.%04lx.%04x.%04x", ctdl_netin_dir, - (long) getpid(), CC->cs_pid, ++seqnum); + (long) getpid(), CCC->cs_pid, ++seqnum); network_fp = fopen(submit_filename, "wb+"); if (network_fp != NULL) { fwrite(smr.ser, smr.len, 1, network_fp); @@ -2663,7 +2709,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* Go back to the room we started from */ lprintf(CTDL_DEBUG, "Returning to original room %s\n", hold_rm); - if (strcasecmp(hold_rm, CC->room.QRname)) + if (strcasecmp(hold_rm, CCC->room.QRname)) usergoto(hold_rm, 0, 1, NULL, NULL); /* For internet mail, generate delivery instructions. @@ -2708,7 +2754,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* * Any addresses to harvest for someone's address book? */ - if ( (CC->logged_in) && (recps != NULL) ) { + if ( (CCC->logged_in) && (recps != NULL) ) { collected_addresses = harvest_collected_addresses(msg); } @@ -2718,7 +2764,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ malloc(sizeof(struct addresses_to_be_filed)); aptr->next = atbf; MailboxName(actual_rm, sizeof actual_rm, - &CC->user, USERCONTACTSROOM); + &CCC->user, USERCONTACTSROOM); aptr->roomname = strdup(actual_rm); aptr->collected_addresses = collected_addresses; atbf = aptr; @@ -2798,7 +2844,7 @@ void quickie_message(char *from, char *fromaddr, char *to, char *room, char *tex msg->cm_fields['N'] = strdup(NODENAME); if (to != NULL) { msg->cm_fields['R'] = strdup(to); - recp = validate_recipients(to); + recp = validate_recipients(to, NULL, 0); } if (subject != NULL) { msg->cm_fields['U'] = strdup(subject); @@ -2819,7 +2865,8 @@ 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 crlf, /* CRLF newlines instead of LF */ + int sock /* socket handle or 0 for this session's client socket */ ) { char buf[1024]; int linelen; @@ -2859,7 +2906,12 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ /* read in the lines of message text one by one */ do { - if (client_getln(buf, (sizeof buf - 3)) < 1) finished = 1; + 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"); @@ -3029,7 +3081,7 @@ struct CtdlMessage *CtdlMakeMessage( msg->cm_fields['M'] = preformatted_text; } else { - msg->cm_fields['M'] = CtdlReadMessageBody("000", config.c_maxmsglen, NULL, 0); + msg->cm_fields['M'] = CtdlReadMessageBody("000", config.c_maxmsglen, NULL, 0, 0); } return(msg); @@ -3041,13 +3093,65 @@ struct CtdlMessage *CtdlMakeMessage( * room. Returns a *CITADEL ERROR CODE* and puts a message in errmsgbuf, or * returns 0 on success. */ -int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, size_t n) { +int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, + size_t n, + const char* RemoteIdentifier, + int PostPublic) { int ra; - if (!(CC->logged_in)) { + if (!(CC->logged_in) && + (PostPublic == POST_LOGGED_IN)) { snprintf(errmsgbuf, n, "Not logged in."); return (ERROR + NOT_LOGGED_IN); } + else if (PostPublic == CHECK_EXISTANCE) { + return (0); // We're Evaling whether a recipient exists + } + else if (!(CC->logged_in)) { + + if ((CC->room.QRflags & QR_READONLY)) { + snprintf(errmsgbuf, n, "Not logged in."); + return (ERROR + NOT_LOGGED_IN); + } + if (CC->room.QRflags2 & QR2_MODERATED) { + snprintf(errmsgbuf, n, "Not logged in Moderation feature not yet implemented!"); + return (ERROR + NOT_LOGGED_IN); + } + if ((PostPublic!=POST_LMTP) &&(CC->room.QRflags2 & QR2_SMTP_PUBLIC) == 0) { + SpoolControl *sc; + char filename[SIZ]; + int found; + + if (RemoteIdentifier == NULL) + { + snprintf(errmsgbuf, n, "Need sender to permit access."); + return (ERROR + USERNAME_REQUIRED); + } + + assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir); + begin_critical_section(S_NETCONFIGS); + if (!read_spoolcontrol_file(&sc, filename)) + { + end_critical_section(S_NETCONFIGS); + snprintf(errmsgbuf, n, + "This mailing list only accepts posts from subscribers."); + return (ERROR + NO_SUCH_USER); + } + end_critical_section(S_NETCONFIGS); + found = is_recipient (sc, RemoteIdentifier); + free_spoolcontrol_struct(&sc); + if (found) { + return (0); + } + else { + snprintf(errmsgbuf, n, + "This mailing list only accepts posts from subscribers."); + return (ERROR + NO_SUCH_USER); + } + } + return (0); + + } if ((CC->user.axlevel < 2) && ((CC->room.QRflags & QR_MAILBOX) == 0)) { @@ -3099,7 +3203,9 @@ 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(char *supplied_recipients, + const char *RemoteIdentifier, + int Flags) { struct recptypes *ret; char *recipients = NULL; char this_recp[256]; @@ -3111,6 +3217,9 @@ struct recptypes *validate_recipients(char *supplied_recipients) { int invalid; struct ctdluser tempUS; struct ctdlroom tempQR; + struct ctdlroom tempQR2; + int err = 0; + char errmsg[SIZ]; int in_quotes = 0; /* Initialize */ @@ -3175,11 +3284,14 @@ struct recptypes *validate_recipients(char *supplied_recipients) { } striplt(this_recp); + if (IsEmptyStr(this_recp)) + break; lprintf(CTDL_DEBUG, "Evaluating recipient #%d: %s\n", num_recps, this_recp); ++num_recps; mailtype = alias(this_recp); mailtype = alias(this_recp); mailtype = alias(this_recp); + j = 0; for (j=0; !IsEmptyStr(&this_recp[j]); ++j) { if (this_recp[j]=='_') { this_recp_cooked[j] = ' '; @@ -3188,7 +3300,9 @@ struct recptypes *validate_recipients(char *supplied_recipients) { this_recp_cooked[j] = this_recp[j]; } } + this_recp_cooked[j] = '\0'; invalid = 0; + errmsg[0] = 0; switch(mailtype) { case MES_LOCAL: if (!strcasecmp(this_recp, "sysop")) { @@ -3217,11 +3331,33 @@ struct recptypes *validate_recipients(char *supplied_recipients) { } else if ( (!strncasecmp(this_recp, "room_", 5)) && (!getroom(&tempQR, &this_recp_cooked[5])) ) { - ++ret->num_room; - if (!IsEmptyStr(ret->recp_room)) { - strcat(ret->recp_room, "|"); + + /* Save room so we can restore it later */ + tempQR2 = CC->room; + CC->room = tempQR; + + /* Check permissions to send mail to this room */ + err = CtdlDoIHavePermissionToPostInThisRoom(errmsg, + sizeof errmsg, + RemoteIdentifier, + Flags + ); + if (err) + { + ++ret->num_error; + invalid = 1; + } + else { + ++ret->num_room; + if (!IsEmptyStr(ret->recp_room)) { + strcat(ret->recp_room, "|"); + } + strcat(ret->recp_room, &this_recp_cooked[5]); } - strcat(ret->recp_room, &this_recp_cooked[5]); + + /* Restore room in case something needs it */ + CC->room = tempQR2; + } else { ++ret->num_error; @@ -3260,15 +3396,16 @@ struct recptypes *validate_recipients(char *supplied_recipients) { break; } if (invalid) { - if (IsEmptyStr(ret->errormsg)) { - snprintf(append, sizeof append, - "Invalid recipient: %s", - this_recp); + if (IsEmptyStr(errmsg)) { + snprintf(append, sizeof append, "Invalid recipient: %s", this_recp); } else { - snprintf(append, sizeof append, ", %s", this_recp); + snprintf(append, sizeof append, "%s", errmsg); } - if ( (strlen(ret->errormsg) + strlen(append)) < SIZ) { + if ( (strlen(ret->errormsg) + strlen(append) + 3) < SIZ) { + if (!IsEmptyStr(ret->errormsg)) { + strcat(ret->errormsg, "; "); + } strcat(ret->errormsg, append); } } @@ -3382,7 +3519,7 @@ void cmd_ent0(char *entargs) /* first check to make sure the request is valid. */ - err = CtdlDoIHavePermissionToPostInThisRoom(errmsg, sizeof errmsg); + err = CtdlDoIHavePermissionToPostInThisRoom(errmsg, sizeof errmsg, NULL, POST_LOGGED_IN); if (err) { cprintf("%d %s\n", err, errmsg); @@ -3450,24 +3587,24 @@ void cmd_ent0(char *entargs) strcpy(bcc, ""); } - valid_to = validate_recipients(recp); + valid_to = validate_recipients(recp, NULL, 0); if (valid_to->num_error > 0) { - cprintf("%d Invalid recipient (To)\n", ERROR + NO_SUCH_USER); + cprintf("%d %s\n", ERROR + NO_SUCH_USER, valid_to->errormsg); free_recipients(valid_to); return; } - valid_cc = validate_recipients(cc); + valid_cc = validate_recipients(cc, NULL, 0); if (valid_cc->num_error > 0) { - cprintf("%d Invalid recipient (CC)\n", ERROR + NO_SUCH_USER); + cprintf("%d %s\n", ERROR + NO_SUCH_USER, valid_cc->errormsg); free_recipients(valid_to); free_recipients(valid_cc); return; } - valid_bcc = validate_recipients(bcc); + valid_bcc = validate_recipients(bcc, NULL, 0); if (valid_bcc->num_error > 0) { - cprintf("%d Invalid recipient (BCC)\n", ERROR + NO_SUCH_USER); + cprintf("%d %s\n", ERROR + NO_SUCH_USER, valid_bcc->errormsg); free_recipients(valid_to); free_recipients(valid_cc); free_recipients(valid_bcc); @@ -3592,7 +3729,7 @@ void cmd_ent0(char *entargs) strcat(all_recps, bcc); } if (!IsEmptyStr(all_recps)) { - valid = validate_recipients(all_recps); + valid = validate_recipients(all_recps, NULL, 0); } else { valid = NULL; @@ -3878,6 +4015,10 @@ void cmd_move(char *args) /* Permit message removal from collaborative delete rooms */ if (CC->room.QRflags2 & QR2_COLLABDEL) permit = 1; + /* Users allowed to post into the target room may move into it too. */ + if ((CC->room.QRflags & QR_MAILBOX) && + (qtemp.QRflags & UA_POSTALLOWED)) permit = 1; + /* User must have access to target room */ if (!(ra & UA_KNOWN)) permit = 0; @@ -4181,7 +4322,8 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ CtdlEncodeBase64( &encoded_message[strlen(encoded_message)], raw_message, - (int)raw_length + (int)raw_length, + 0 ); } else { @@ -4309,7 +4451,7 @@ int CtdlIsMe(char *addr, int addr_buf_len) struct recptypes *recp; int i; - recp = validate_recipients(addr); + recp = validate_recipients(addr, NULL, 0); if (recp == NULL) return(0); if (recp->num_local == 0) {