extern struct config config;
+char *msgkeys[] = {
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "",
+ "from",
+ "", "", "", "", "", "",
+ "hnod",
+ "msgn",
+ "", "", "",
+ "text",
+ "node",
+ "room",
+ "path",
+ "",
+ "rcpt",
+ ""
+ "time",
+ "subj",
+ "",
+ "",
+ "",
+ "",
+ "zaps"
+};
+
/*
* This function is self explanatory.
* (What can I say, I'm in a weird mood today...)
}
+
+/* Determine if a given message matches the fields in a message template.
+ * Return 0 for a successful match.
+ */
+int CtdlMsgCmp(struct CtdlMessage *msg, struct CtdlMessage *template) {
+ int i;
+
+ /* If there aren't any fields in the template, all messages will
+ * match.
+ */
+ if (template == NULL) return(0);
+
+ /* Null messages are bogus. */
+ if (msg == NULL) return(1);
+
+ for (i='A'; i<='Z'; ++i) {
+ if (template->cm_fields[i] != NULL) {
+ if (msg->cm_fields[i] == NULL) {
+ return 1;
+ }
+ if (strcasecmp(msg->cm_fields[i],
+ template->cm_fields[i])) return 1;
+ }
+ }
+
+ /* All compares succeeded: we have a match! */
+ return 0;
+}
+
+
+
+
/*
* API function to perform an operation for each qualifying message in the
* current room.
*/
void CtdlForEachMessage(int mode, long ref,
char *content_type,
+ struct CtdlMessage *compare,
void (*CallBack) (long msgnum))
{
int num_msgs = 0;
long thismsg;
struct SuppMsgInfo smi;
+ struct CtdlMessage *msg;
/* Learn about the user and room in question */
get_mm();
}
num_msgs = sort_msglist(msglist, num_msgs);
+
+ /* If a template was supplied, filter out the messages which
+ * don't match. (This could induce some delays!)
+ */
+ if (num_msgs > 0) {
+ if (compare != NULL) {
+ for (a = 0; a < num_msgs; ++a) {
+ msg = CtdlFetchMessage(msglist[a]);
+ if (msg != NULL) {
+ if (CtdlMsgCmp(msg, compare)) {
+ msglist[a] = 0L;
+ }
+ CtdlFreeMessage(msg);
+ }
+ }
+ }
+ }
+
/*
* Now iterate through the message list, according to the
{
int mode = 0;
char which[256];
+ char buf[256];
+ char tfield[256];
+ char tvalue[256];
int cm_ref = 0;
+ int i;
+ int with_template = 0;
+ struct CtdlMessage *template = NULL;
extract(which, cmdbuf, 0);
cm_ref = extract_int(cmdbuf, 1);
+ with_template = extract_int(cmdbuf, 2);
mode = MSGS_ALL;
strcat(which, " ");
cprintf("%d not logged in\n", ERROR + NOT_LOGGED_IN);
return;
}
- cprintf("%d Message list...\n", LISTING_FOLLOWS);
- CtdlForEachMessage(mode, cm_ref, NULL, simple_listing);
+
+ if (with_template) {
+ cprintf("%d Send template then receive message list\n",
+ START_CHAT_MODE);
+ template = (struct CtdlMessage *)
+ mallok(sizeof(struct CtdlMessage));
+ memset(template, 0, sizeof(struct CtdlMessage));
+ while(client_gets(buf), strcmp(buf,"000")) {
+ extract(tfield, buf, 0);
+ extract(tvalue, buf, 1);
+ for (i='A'; i<='Z'; ++i) if (msgkeys[i]!=NULL) {
+ if (!strcasecmp(tfield, msgkeys[i])) {
+ template->cm_fields[i] =
+ strdoop(tvalue);
+ }
+ }
+ }
+ }
+ else {
+ cprintf("%d Message list...\n", LISTING_FOLLOWS);
+ }
+
+ CtdlForEachMessage(mode, cm_ref, NULL, template, simple_listing);
+ if (template != NULL) CtdlFreeMessage(template);
cprintf("000\n");
}
void output_message(char *msgid, int mode, int headers_only)
{
long msg_num;
- int a, i;
+ int a, i, k;
char buf[1024];
time_t xtime;
CIT_UBYTE ch;
+ char allkeys[256];
struct CtdlMessage *TheMessage = NULL;
if ((mode == MT_CITADEL) || (mode == MT_MIME)) {
- if (TheMessage->cm_fields['P']) {
- cprintf("path=%s\n", TheMessage->cm_fields['P']);
- }
- if (TheMessage->cm_fields['I']) {
- cprintf("msgn=%s\n", TheMessage->cm_fields['I']);
- }
- if (TheMessage->cm_fields['T']) {
- cprintf("time=%s\n", TheMessage->cm_fields['T']);
- }
if (TheMessage->cm_fields['A']) {
strcpy(buf, TheMessage->cm_fields['A']);
PerformUserHooks(buf, (-1L), EVT_OUTPUTMSG);
}
cprintf("\n");
}
- if (TheMessage->cm_fields['O']) {
- cprintf("room=%s\n", TheMessage->cm_fields['O']);
- }
- if (TheMessage->cm_fields['N']) {
- cprintf("node=%s\n", TheMessage->cm_fields['N']);
- }
- if (TheMessage->cm_fields['H']) {
- cprintf("hnod=%s\n", TheMessage->cm_fields['H']);
- }
- if (TheMessage->cm_fields['R']) {
- cprintf("rcpt=%s\n", TheMessage->cm_fields['R']);
- }
- if (TheMessage->cm_fields['U']) {
- cprintf("subj=%s\n", TheMessage->cm_fields['U']);
- }
- if (TheMessage->cm_fields['Z']) {
- cprintf("zaps=%s\n", TheMessage->cm_fields['Z']);
+
+ strcpy(allkeys, FORDER);
+ for (i=0; i<strlen(allkeys); ++i) {
+ k = (int) allkeys[i];
+ if ((k != 'A') && (k != 'M')) {
+ if (TheMessage->cm_fields[k] != NULL)
+ cprintf("%s=%s\n",
+ msgkeys[k],
+ TheMessage->cm_fields[k]
+ );
+ }
}
+
}
/* begin header processing loop for RFC822 transfer format */
This command obtains a listing of all the messages in the current room
which the client may request. This command may be passed a single parameter:
either "all", "old", or "new" to request all messages, only old messages, or
-new messages. Or it may be passed two parameters: "last" plus a number, in which
-case that many message pointers will be returned, or "first" plus a number, for
-the corresponding effect. If no parameters are specified, "all" is assumed.
+new messages. Or it may be passed two parameters: "last" plus a number, in
+which case that many message pointers will be returned, or "first" plus a
+number, for the corresponding effect. If no parameters are specified, "all"
+is assumed.
- In Citadel/UX 5.00 and above, the client may also specify "gt" plus a number, to
-list all messages in the current room with a message number greater than the one
-specified.
+ In Citadel/UX 5.00 and above, the client may also specify "gt" plus a number,
+to list all messages in the current room with a message number greater than
+the one specified.
+
+ The third argument, valid only in Citadel/UX 5.60 and above, may be either
+0 or 1. If it is 1, this command behaves differently: before a listing is
+returned, the client must transmit a list of fields to search for. The field
+headers are listed below in the writeup for the "MSG0" command.
- This command can return two possible results. An ERROR code may be returned
+ This command can return three possible results. An ERROR code may be returned
if no user is currently logged in or if something else went wrong. Otherwise,
LISTING_FOLLOWS will be returned, and the listing will consist of zero or
more message numbers, one per line. The listing ends, as always, with the
string "000" alone on a line by itself. The listed message numbers can be used
-to request messages from the system.
+to request messages from the system. If "search mode" is being used, the
+server will return START_CHAT_MODE, and the client is expected to transmit
+the search criteria, and then read the message list.
+
+ Since this is somewhat complex, here are some examples:
+
+ Example 1: Read all new messages
+
+ Client: MSGS NEW
+ Server: 100 Message list...
+ 523218
+ 523293
+ 523295
+ 000
+
+ Example 2: Read the last five messages
+
+ Client: MSGS LAST|5
+ Server: 100 Message list...
+ 523190
+ 523211
+ 523218
+ 523293
+ 523295
+ 000
+
+ Example 3: Read all messages written by "IGnatius T Foobar"
+
+ Client: MSGS ALL|0|1
+ Server: 800 Send template then receive message list
+ Client: from|IGnatius T Foobar
+ 000
+ Server: 518604
+ 519366
+ 519801
+ 520201
+ 520268
+ 520805
+ 520852
+ 521579
+ 521720
+ 522571
+ 000
+
+ Note that in "search mode" the client may specify any number of search
+criteria. These criteria are applied with an AND logic.
+
MSG0 (read MeSsaGe, mode 0)
This is a command used to read the text of a message. "Mode 0" implies that
room= The name of the room the message originated in.
node= The short node name of the system this message originated on.
hnod= The long node name of the system this message originated on.
+ zaps= The id/node of a message which this one zaps (supersedes).
text Note that there is no "=" after the word "text". This string
signifies that the message text begins on the next line.