X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fctdlproto%2Fserv_messages.c;h=6550e44211ca4d1afe078a5adcf3902215c1b3cd;hb=0387f48886a9395d89eaca01cd40ab751610426f;hp=31e48cb8c3077409ae9827f84b303e51208dd267;hpb=7c94d5bb68f1c448770d31205ec5ae12bd8a02ed;p=citadel.git diff --git a/citadel/modules/ctdlproto/serv_messages.c b/citadel/modules/ctdlproto/serv_messages.c index 31e48cb8c..6550e4421 100644 --- a/citadel/modules/ctdlproto/serv_messages.c +++ b/citadel/modules/ctdlproto/serv_messages.c @@ -1,7 +1,7 @@ /* * represent messages to the citadel clients * - * Copyright (c) 1987-2015 by the citadel.org team + * Copyright (c) 1987-2020 by the citadel.org team * * This program is open source software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3. @@ -40,24 +40,100 @@ void simple_listing(long msgnum, void *userdata) void headers_listing(long msgnum, void *userdata) { struct CtdlMessage *msg; + int output_mode = *(int *)userdata; - msg = CtdlFetchMessage(msgnum, 0, 1); + msg = CtdlFetchMessage(msgnum, 0); if (msg == NULL) { - cprintf("%ld|0|||||\n", msgnum); + cprintf("%ld|0|||||||\n", msgnum); return; } - cprintf("%ld|%s|%s|%s|%s|%s|\n", + // change all vertical bars in the subject to hyphens so it doesn't screw up the protocol + if (!CM_IsEmpty(msg, eMsgSubject)) { + char *p; + for (p=msg->cm_fields[eMsgSubject]; *p; p++) { + if (*p == '|') { + *p = '-'; + } + } + } + + // output all fields except the references hash + cprintf("%ld|%s|%s|%s|%s|%s", msgnum, (!CM_IsEmpty(msg, eTimestamp) ? msg->cm_fields[eTimestamp] : "0"), (!CM_IsEmpty(msg, eAuthor) ? msg->cm_fields[eAuthor] : ""), - (!CM_IsEmpty(msg, eNodeName) ? msg->cm_fields[eNodeName] : ""), + CtdlGetConfigStr("c_nodename"), // no more nodenames anymore (!CM_IsEmpty(msg, erFc822Addr) ? msg->cm_fields[erFc822Addr] : ""), (!CM_IsEmpty(msg, eMsgSubject) ? msg->cm_fields[eMsgSubject] : "") ); + + if (output_mode == MSG_HDRS_THREADS) { // field view with thread hashes + + // output the references hash + cprintf ("|%d|", + (!CM_IsEmpty(msg, emessageId) ? HashLittle(msg->cm_fields[emessageId],strlen(msg->cm_fields[emessageId])) : 0) + ); + + // output the references hash (yes it's ok that we're trashing the source buffer by doing this) + if (!CM_IsEmpty(msg, eWeferences)) { + char *token; + char *rest = msg->cm_fields[eWeferences]; + char *prev = rest; + while((token = strtok_r(rest, "|", &rest))) { + cprintf("%d%s", HashLittle(token,rest-prev-(*rest==0?0:1)), (*rest==0?"":",")); + prev = rest; + } + } + + cprintf("|\n"); + } + + else { // field view with no threads, subject extends out forever + cprintf("\n"); + } + CM_Free(msg); } +typedef struct _msg_filter{ + HashList *Filter; + HashPos *p; + StrBuf *buffer; +}msg_filter; + +void headers_brief_filter(long msgnum, void *userdata) +{ + long i, l; + struct CtdlMessage *msg; + msg_filter *flt = (msg_filter*) userdata; + + l = GetCount(flt->Filter); + msg = CtdlFetchMessage(msgnum, 0); + StrBufPrintf(flt->buffer, "%ld", msgnum); + if (msg == NULL) { + for (i = 0; i < l; i++) { + StrBufAppendBufPlain(flt->buffer, HKEY("|"), 0); + } + } + else { + const char *k; + long len; + void *v; + RewindHashPos(flt->Filter, flt->p, 0); + while (GetNextHashPos(flt->Filter, flt->p, &len, &k, &v)) { + eMsgField f = (eMsgField) v; + + StrBufAppendBufPlain(flt->buffer, HKEY("|"), 0); + if (!CM_IsEmpty(msg, f)) { + StrBufAppendBufPlain(flt->buffer, CM_KEY(msg, f), 0); + } + } + } + StrBufAppendBufPlain(flt->buffer, HKEY("\n"), 0); + cputbuf(flt->buffer); +} + /* * Back end for the MSGS command: output EUID header. */ @@ -65,7 +141,7 @@ void headers_euid(long msgnum, void *userdata) { struct CtdlMessage *msg; - msg = CtdlFetchMessage(msgnum, 0, 1); + msg = CtdlFetchMessage(msgnum, 0); if (msg == NULL) { cprintf("%ld||\n", msgnum); return; @@ -92,9 +168,9 @@ void cmd_msgs(char *cmdbuf) char tfield[256]; char tvalue[256]; int cm_ref = 0; - int i; int with_template = 0; struct CtdlMessage *template = NULL; + msg_filter filt; char search_string[1024]; ForEachMsgCallback CallBack; @@ -104,18 +180,23 @@ void cmd_msgs(char *cmdbuf) cm_ref = extract_int(cmdbuf, 1); extract_token(search_string, cmdbuf, 1, '|', sizeof search_string); with_template = extract_int(cmdbuf, 2); - 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; + int output_mode = extract_int(cmdbuf, 3); + switch (output_mode) { + default: + case MSG_HDRS_BRIEF: + CallBack = simple_listing; + break; + case MSG_HDRS_ALL: + case MSG_HDRS_THREADS: + CallBack = headers_listing; + break; + case MSG_HDRS_EUID: + CallBack = headers_euid; + break; + case MSG_HDRS_BRIEFFILTER: + with_template = 2; + CallBack = headers_brief_filter; + break; } strcat(which, " "); @@ -142,7 +223,8 @@ void cmd_msgs(char *cmdbuf) return; } - if (with_template) { + if (with_template == 1) { + memset(buf, 0, 5); unbuffer_output(); cprintf("%d Send template then receive message list\n", START_CHAT_MODE); @@ -153,29 +235,66 @@ void cmd_msgs(char *cmdbuf) template->cm_anon_type = MES_NORMAL; while(client_getln(buf, sizeof buf) >= 0 && strcmp(buf,"000")) { + eMsgField f; long tValueLen; - extract_token(tfield, buf, 0, '|', sizeof tfield); - tValueLen = extract_token(tvalue, buf, 1, '|', sizeof tvalue); - for (i='A'; i<='Z'; ++i) if (msgkeys[i]!=NULL) { - if (!strcasecmp(tfield, msgkeys[i])) { - CM_SetField(template, i, tvalue, tValueLen); + + tValueLen = extract_token(tfield, buf, 0, '|', sizeof tfield); + if ((tValueLen == 4) && GetFieldFromMnemonic(&f, tfield)) + { + tValueLen = extract_token(tvalue, buf, 1, '|', sizeof tvalue); + if (tValueLen >= 0) { + CM_SetField(template, f, tvalue, tValueLen); } } } buffer_output(); } + else if (with_template == 2) { + long i = 0; + memset(buf, 0, 5); + cprintf("%d Send list of headers\n", + START_CHAT_MODE); + filt.Filter = NewHash(1, lFlathash); + filt.buffer = NewStrBufPlain(NULL, 1024); + while(client_getln(buf, sizeof buf) >= 0 && strcmp(buf,"000")) { + eMsgField f; + + if (GetFieldFromMnemonic(&f, buf)) + { + Put(filt.Filter, LKEY(i), (void*)f, reference_free_handler); + i++; + } + } + filt.p = GetNewHashPos(filt.Filter, 0); + buffer_output(); + } else { cprintf("%d \n", LISTING_FOLLOWS); } - CtdlForEachMessage(mode, - ( (mode == MSGS_SEARCH) ? 0 : cm_ref ), - ( (mode == MSGS_SEARCH) ? search_string : NULL ), - NULL, - template, - CallBack, - NULL); - if (template != NULL) CM_Free(template); + if (with_template < 2) { + CtdlForEachMessage(mode, + ( (mode == MSGS_SEARCH) ? 0 : cm_ref ), + ( (mode == MSGS_SEARCH) ? search_string : NULL ), + NULL, + template, + CallBack, + &output_mode); + if (template != NULL) CM_Free(template); + } + else { + CtdlForEachMessage(mode, + ( (mode == MSGS_SEARCH) ? 0 : cm_ref ), + ( (mode == MSGS_SEARCH) ? search_string : NULL ), + NULL, + NULL, + CallBack, + &filt); + DeleteHashPos(&filt.p); + DeleteHash(&filt.Filter); + FreeStrBuf(&filt.buffer); + + } cprintf("000\n"); } @@ -210,46 +329,6 @@ void cmd_msg2(char *cmdbuf) } - -/* - * display a message (mode 3 - IGnet raw format - internal programs only) - */ -void cmd_msg3(char *cmdbuf) -{ - long msgnum; - struct CtdlMessage *msg = NULL; - struct ser_ret smr; - - if (CC->internal_pgm == 0) { - cprintf("%d This command is for internal programs only.\n", - ERROR + HIGHER_ACCESS_REQUIRED); - return; - } - - msgnum = extract_long(cmdbuf, 0); - msg = CtdlFetchMessage(msgnum, 1, 1); - if (msg == NULL) { - cprintf("%d Message %ld not found.\n", - ERROR + MESSAGE_NOT_FOUND, msgnum); - return; - } - - CtdlSerializeMessage(&smr, msg); - CM_Free(msg); - - if (smr.len == 0) { - cprintf("%d Unable to serialize message\n", - ERROR + INTERNAL_ERROR); - return; - } - - cprintf("%d %ld\n", BINARY_FOLLOWS, (long)smr.len); - client_write((char *)smr.ser, (int)smr.len); - free(smr.ser); -} - - - /* * Display a message using MIME content types */ @@ -264,7 +343,6 @@ void cmd_msg4(char *cmdbuf) } - /* * Client tells us its preferred message format(s) */ @@ -598,7 +676,7 @@ void cmd_ent0(char *entargs) } free(all_recps); - if ((valid != NULL) && (valid->num_room == 1)) + if ((valid != NULL) && (valid->num_room == 1) && !IsEmptyStr(valid->recp_orgroom)) { /* posting into an ML room? set the envelope from * to the actual mail address so others get a valid @@ -608,7 +686,7 @@ void cmd_ent0(char *entargs) } if (msg != NULL) { - msgnum = CtdlSubmitMsg(msg, valid, "", QP_EADDR); + msgnum = CtdlSubmitMsg(msg, valid, ""); if (do_confirm) { cprintf("%ld\n", msgnum); @@ -806,7 +884,6 @@ CTDL_MODULE_INIT(ctdl_message) 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");