/* logical.c */ #include "ml.h" #define SECONDS_PER_DAY (60*60*24) static char lan[4]; static char lheure[64]; char *mois[12]= { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC", }; static int dpm[]= {/*dec - dec */ 31, 30, 28, 31, 30, 31, 30, 31, 31, 31, 31, 30, 31 }; static int leap_dpm[]= {/*dec - dec */ 31, 30, 29, 31, 30, 31, 30, 31, 31, 31, 31, 30, 31 }; /* * Macro definitions. These are filter criteria which are expanded * at search time and contain more than one filter rule. for instance, * "conversant john" is the same as "from john or to john or cc john". */ static LEAF recipient_macro[]= { { "CC", NO_OP, FALSE, pred_field, NULL }, { "TO", OR_OP, FALSE, pred_field, NULL }, { NULL, NO_OP, FALSE, pred_simple, NULL } }; static LEAF correspondent_macro[]= { { "FROM", NO_OP, FALSE, pred_field, NULL }, { "TO", OR_OP, FALSE, pred_field, NULL }, { NULL, NO_OP, FALSE, pred_simple, NULL } }; static LEAF conversant_macro[]= { { "FROM", NO_OP, FALSE, pred_field, NULL }, { "TO", OR_OP, FALSE, pred_field, NULL }, { "CC", OR_OP, FALSE, pred_field, NULL }, { NULL, NO_OP, FALSE, pred_simple, NULL } }; static LEAFMACRO macro_petals[]= { { RECIPIENT_MACRO, recipient_macro, 2 }, { CORRESPONDENT_MACRO, correspondent_macro, 2 }, { CONVERSANT_MACRO, conversant_macro, 3 }, { NULL, NULL, 0 } }; #ifdef __STDC__ Message_List *apply_op_to_operands(Mailbox *mailbox, BOOLEAN_OPERATOR op, Message_List **list1, Message_List **list2) #else Message_List *apply_op_to_operands(mailbox,op,list1,list2) Mailbox *mailbox; BOOLEAN_OPERATOR op; Message_List **list1; Message_List **list2; #endif { Message_List *result = NULL; switch(op) { case AND_OP: conjunct_and(mailbox,*list1,*list2); result = mailbox->found; mailbox->found = NULL; break; /* * A no_op is treated as an or_op because we don't know which of the * two lists to preserve -- one of them will be empty. The other needs * to be returned. Or'ing the two gives us the right result, regardless. */ case OR_OP: case NO_OP: conjunct_or(mailbox,*list1,*list2); result = mailbox->found; mailbox->found = NULL; break; default: /* this shouldn't ever happen. */ break; } free_message_list(*list1,TRUE,FALSE); *list1 = NULL; free_message_list(*list2,TRUE,FALSE); *list2 = NULL; return(result); } #ifdef __STDC__ LEAFMACRO *macro_expansion_required(LEAF *leaf) #else LEAFMACRO *macro_expansion_required(leaf) LEAF *leaf; #endif { int i; LEAFMACRO *lm = macro_petals; char tmp[FILEBUFFLEN]; strcpy(tmp, leaf->predicate); /* * We have either * predicate "FIELD" * or * predicate * In the former case we NUL terminate the predicate * for comparison to our macro predicates */ if (leaf->predicate_type == pred_field || leaf->predicate_type == pred_dynamic_field) { /* select the predicate only - it is terminated by a space */ strtok(tmp, " "); /* NULL out the SPACE */ } for (i = 0; lm->macro_name; ++i, ++lm) if (strcasecmp(lm->macro_name, tmp) == 0) return lm; return NIL; } #ifdef __STDC__ void do_imap_macro_mail_search(Mailbox *mailbox, Lview *parent, LEAFMACRO *lm, LEAF *petal) #else void do_imap_macro_mail_search(mailbox, parent, lm, petal) Mailbox *mailbox; Lview *parent; LEAFMACRO *lm; /* The expansion rules */ LEAF *petal; /* The macro which we expand */ #endif { LEAF *macro= lm->leaves; int n_leaves= lm->n_leaves; int i; char field[FILEBUFFLEN], *fptr= field; Boolean local_ok= TRUE; Message_List *result = NULL; Message_List *current = NULL; /* see if our MACRO predicate requires a field */ if (petal->predicate_type == pred_field || petal->predicate_type == pred_dynamic_field) { /* extract the field */ strcpy(field, petal->predicate); /* "pred field" */ fptr = strchr(field,(int) SPACECHAR) + 1; /* skip the space */ } else fptr = NULL; /* EXPAND our macro here one leaf at a time ... */ for (i = 0; i < n_leaves; ++i, ++macro) { char pred[FILEBUFFLEN]; /* for expanded predicate */ /* * Contruct a search predicate with a field if necessary. * Our macros NEVER include them since they are dynamic */ strcpy(pred, macro->predicate); /* get the MACRO predicate */ if ((petal->predicate_type == pred_field || petal->predicate_type == pred_dynamic_field) && macro->predicate_type == pred_field) { /* double check OK */ strcat(pred, SPACESTR); /* adjunct the FIELD */ strcat(pred, fptr); } /* * Dispatch the search */ free_message_list(mailbox->found,TRUE,FALSE); mailbox->found = NULL; local_ok = local_search(mailbox, parent, pred); if (local_ok == FALSE) remote_search(mailbox, parent, pred); /* * Save the current results. */ current = mailbox->found; mailbox->found = NULL; /* * Now accumulate the results with any operands */ if(macro->operator == NO_OP) { result = current; current = NULL; } else result = apply_op_to_operands(mailbox, macro->operator, &result, ¤t); } /* * Our accumulated results are in "result". We'll make it appear * as though this was a simple mailbox search, (results accumulated * into "mailbox->found") since that's what the dispatcher is expecting. * We're done with the intermediate list. Free its memory. */ free_message_list(current, TRUE, FALSE); mailbox->found = result; return; } #ifdef __STDC__ void remote_search(Mailbox *mailbox, Lview *parent, char *predicate) #else void remote_search(mailbox, parent, predicate) Mailbox *mailbox; Lview *parent; char *predicate; #endif { Message_List *result; free_message_list(mailbox->found,TRUE,FALSE); mailbox->found = NULL; mail_search(mailbox->mailstream,predicate); result = mailbox->found; mailbox->found = NULL; conjunct_and(mailbox,result,parent->message_list); free_message_list(result,TRUE,FALSE); } /* * Do the search on the given mail box */ #ifdef __STDC__ void do_imap_mail_search(Mailbox *mailbox, Lview *parent, LEAF *leaf) #else void do_imap_mail_search(mailbox, parent, leaf) Mailbox *mailbox; Lview *parent; LEAF *leaf; #endif { Boolean local_ok = TRUE; /* * Some searches are dispatched to the server, * and others we do locally from our cache */ free_message_list(mailbox->found,TRUE,FALSE); mailbox->found = NULL; local_ok = local_search(mailbox, parent, leaf->predicate); if (local_ok == FALSE) remote_search(mailbox, parent, leaf->predicate); return; } /* * Does a search on all search petals, and accumulates the results * into result */ #ifdef __STDC__ Message_List *do_imap_search(Mailbox *mailbox, Lview *parent, LEAF *petal) #else Message_List *do_imap_search(mailbox, parent, petal) Mailbox *mailbox; Lview *parent; LEAF *petal; #endif { LEAF *leaf = petal; char *old_pred; char *new_pred; Message_List *current = NULL; Message_List *result = NULL; /* run down the petals accumulating the results of * each search */ while (leaf) { LEAFMACRO *lm; new_pred = update_dynamic_predicates(leaf); if(new_pred) { /* Temporarily switch the predicates for the search */ old_pred = leaf->predicate; leaf->predicate = new_pred; } else old_pred = NULL; if ((lm = macro_expansion_required(leaf)) != NIL) do_imap_macro_mail_search(mailbox, parent, lm, leaf); else do_imap_mail_search(mailbox, parent, leaf); if (old_pred) { fs_give((void **) &new_pred); leaf->predicate = old_pred; } /* If we have found something, hold on to it */ current = mailbox->found; /* reset the search results */ mailbox->found = NULL; /* Look for negation */ if(leaf->atomic_not == TRUE) { negate_search(mailbox,current,parent->message_list); current = mailbox->found; mailbox->found = NULL; } /* apply operation to the result, EG: a OR b */ if(leaf->operator == NO_OP) { result = current; current = NULL; } else result = apply_op_to_operands(mailbox, leaf->operator, &result, ¤t); leaf = leaf->next; } if(current) free_message_list(current,TRUE,FALSE); return(result); } #ifdef __STDC__ void set_leading_lan(void) #else void set_leading_lan() #endif { struct timeval tp; struct timezone tzp; char *date; gettimeofday(&tp, &tzp); date = ctime((time_t *) &tp.tv_sec); lan[0] = date[20]; lan[1] = date[21]; lan[2] = '\0'; } #ifdef __STDC__ char *set_today(void) #else char *set_today() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_hier(void) #else char *set_hier() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; horloge -= SECONDS_PER_DAY; temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_mois_dernier(void) #else char *set_mois_dernier() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; int days_last_month; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); /* Take us to the debut of last month */ /* THe debut of this month */ horloge = horloge - ((temps->tm_mday - 1)* SECONDS_PER_DAY); /* Our month tables begin with dec, and tm_mon is 0 - 11, ie, tm_mon + 1 * indexes THIS MONTH in our tables, alors tm_mon indexes LAST MONTH: */ days_last_month = ((temps->tm_year % 4) == 0) ? leap_dpm[temps->tm_mon] : dpm[temps->tm_mon]; horloge -= days_last_month * SECONDS_PER_DAY; temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_mois_courant(void) #else char *set_mois_courant() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); sprintf(lheure, "\" 1-%s-%s%2d\"", mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_january(void) #else char *set_january() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); sprintf(lheure, "\" 1-JAN-%s%2d\"", lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_february(void) #else char *set_february() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; int year; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); year = temps->tm_year; sprintf(lheure, "\" 1-FEB-%s%2d\"", lan, year); return lheure; } #ifdef __STDC__ char *set_march(void) #else char *set_march() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; int year; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); year = temps->tm_year; sprintf(lheure, "\" 1-MAR-%s%2d\"", lan, year); return lheure; } #ifdef __STDC__ char *set_april(void) #else char *set_april() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; int year; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); year = temps->tm_year; sprintf(lheure, "\" 1-APR-%s%2d\"", lan, year); return lheure; } #ifdef __STDC__ char *set_may(void) #else char *set_may() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; int year; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); year = temps->tm_year; sprintf(lheure, "\" 1-MAY-%s%2d\"", lan, year); return lheure; } #ifdef __STDC__ char *set_june(void) #else char *set_june() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; int year; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); year = temps->tm_year; sprintf(lheure, "\" 1-JUN-%s%2d\"", lan, year); return lheure; } #ifdef __STDC__ char *set_july(void) #else char *set_july() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; int year; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); year = temps->tm_year; sprintf(lheure, "\" 1-JUL-%s%2d\"", lan, year); return lheure; } #ifdef __STDC__ char *set_august(void) #else char *set_august() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; int year; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); year = temps->tm_year; sprintf(lheure, "\" 1-AUG-%s%2d\"", lan, year); return lheure; } #ifdef __STDC__ char *set_september(void) #else char *set_september() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; int year; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); year = temps->tm_year; sprintf(lheure, "\" 1-SEP-%s%2d\"", lan, year); return lheure; } #ifdef __STDC__ char *set_october(void) #else char *set_october() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; int year; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); year = temps->tm_year; sprintf(lheure, "\" 1-OCT-%s%2d\"", lan, year); return lheure; } #ifdef __STDC__ char *set_november(void) #else char *set_november() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; int year; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); year = temps->tm_year; sprintf(lheure, "\" 1-NOV-%s%2d\"", lan, year); return lheure; } #ifdef __STDC__ char *set_december(void) #else char *set_december() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; int year; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); year = temps->tm_year; sprintf(lheure, "\" 1-DEC-%s%2d\"", lan, year); return lheure; } #ifdef __STDC__ char *set_sunday(void) #else char *set_sunday() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); horloge -= temps->tm_wday * SECONDS_PER_DAY; temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_monday(void) #else char *set_monday() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); horloge -= (temps->tm_wday - 1) * SECONDS_PER_DAY; temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_tuesday(void) #else char *set_tuesday() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); horloge -= (temps->tm_wday - 2) * SECONDS_PER_DAY; temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_wednesday(void) #else char *set_wednesday() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); horloge -= (temps->tm_wday - 3) * SECONDS_PER_DAY; temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_thursday(void) #else char *set_thursday() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); horloge -= (temps->tm_wday - 4) * SECONDS_PER_DAY; temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_friday(void) #else char *set_friday() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); horloge -= (temps->tm_wday - 5) * SECONDS_PER_DAY; temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_saturday(void) #else char *set_saturday() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); horloge -= (temps->tm_wday - 6) * SECONDS_PER_DAY; temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_lastsunday(void) #else char *set_lastsunday() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); horloge = horloge - (temps->tm_wday * SECONDS_PER_DAY) - (7 * SECONDS_PER_DAY); temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_lastmonday(void) #else char *set_lastmonday() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); horloge = horloge - (temps->tm_wday * SECONDS_PER_DAY) - (6 * SECONDS_PER_DAY); temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_lasttuesday(void) #else char *set_lasttuesday() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); horloge = horloge - (temps->tm_wday * SECONDS_PER_DAY) - (5 * SECONDS_PER_DAY); temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_lastwednesday(void) #else char *set_lastwednesday() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); horloge = horloge - (temps->tm_wday * SECONDS_PER_DAY) - (4 * SECONDS_PER_DAY); temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_lastthursday(void) #else char *set_lastthursday() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); horloge = horloge - (temps->tm_wday * SECONDS_PER_DAY) - (3 * SECONDS_PER_DAY); temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_lastfriday(void) #else char *set_lastfriday() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); horloge = horloge - (temps->tm_wday * SECONDS_PER_DAY) - (2 * SECONDS_PER_DAY); temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ char *set_lastsaturday(void) #else char *set_lastsaturday() #endif { time_t horloge; struct tm *temps; struct timeval tp; struct timezone tzp; gettimeofday(&tp, &tzp); horloge = (time_t)tp.tv_sec; temps = localtime(&horloge); horloge = horloge - (temps->tm_wday * SECONDS_PER_DAY) - (1 * SECONDS_PER_DAY); temps = localtime(&horloge); sprintf(lheure, "\"%2d-%s-%s%2d\"", temps->tm_mday, mois[temps->tm_mon], lan, temps->tm_year); return lheure; } #ifdef __STDC__ void conjunct_and(Mailbox *mailbox, Message_List *list1, Message_List *list2) #else void conjunct_and(mailbox,list1, list2) Mailbox *mailbox; Message_List *list1; Message_List *list2; #endif { Message_List *ptr1; Message_List *ptr2; Boolean found_it = FALSE; free_message_list(mailbox->found, TRUE, FALSE); mailbox->found = NULL; for(ptr1 = list1; ptr1; ptr1 = ptr1->next) { found_it = FALSE; for(ptr2 = list2; ptr2; ptr2 = ptr2->next) { if(ptr1->message == ptr2->message) { found_it = TRUE; break; } } if(found_it == TRUE) mm_searched(mailbox->mailstream,ptr1->message->msgno); } return; } #ifdef __STDC__ void conjunct_or(Mailbox *mailbox, Message_List *list1, Message_List *list2) #else void conjunct_or(mailbox,list1, list2) Mailbox *mailbox; Message_List *list1; Message_List *list2; #endif { Message_List *ptr; Message_List *ptr2; /* * Not easy. First we have to combine the two lists into an intermediate * list, and then weed out duplicates. To do this, efficiently, * we sort the intermediate list, since there may be no logical ordering. */ free_message_list(mailbox->found, TRUE, FALSE); mailbox->found = NULL; for(ptr = list1; ptr; ptr = ptr->next) mm_searched(mailbox->mailstream,ptr->message->msgno); for(ptr = list2; ptr; ptr = ptr->next) mm_searched(mailbox->mailstream,ptr->message->msgno); ptr = sort_message_list(mailbox->found,REP_ASCENDING); mailbox->found = NULL; for(ptr2 = ptr; ptr2; ptr2 = ptr2->next) { if((ptr2->next != NULL) && (ptr2->message != NULL) && (ptr2->next->message != NULL) && (ptr2->next->message->msgno == ptr2->message->msgno)) ptr2 = ptr2->next; if(ptr2->message) mm_searched(mailbox->mailstream,ptr2->message->msgno); } free_message_list(ptr,TRUE,FALSE); return; } #ifdef __STDC__ void negate_search(Mailbox *mailbox, Message_List *list1, Message_List *list2) #else void negate_search(mailbox,list1,list2) Mailbox *mailbox; Message_List *list1; Message_List *list2; #endif { Message_List *ptr; Message_List *message_list; Boolean found_it = FALSE; for(message_list = list2; message_list; message_list = message_list->next) { found_it = FALSE; for(ptr = list1; ptr; ptr = ptr->next) { if(ptr->message == message_list->message) { found_it = TRUE; break; } } if(found_it == FALSE) mm_searched(mailbox->mailstream, message_list->message->msgno); } free_message_list(list1,TRUE,FALSE); return; } /* * Each of the functions below return TRUE unless the search should * be defaulted to the server. */ #ifdef __STDC__ Boolean local_new_search(Mailbox *mailbox, Message_List *parent) #else Boolean local_new_search(mailbox,parent) Mailbox *mailbox; Message_List *parent; #endif { Message_List *message_list; MESSAGECACHE *elt; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->longcache) { elt = &(message_list->message->longcache->elt); if((! elt->seen) && elt->recent) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return(TRUE); } /* * Do a search on the mailbox cache for deleted messages */ #ifdef __STDC__ Boolean local_deleted_search(Mailbox *mailbox, Message_List *parent) #else Boolean local_deleted_search(mailbox,parent) Mailbox *mailbox; Message_List *parent; #endif { Message_List *message_list; MESSAGECACHE *elt; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->longcache) { elt = &(message_list->message->longcache->elt); if(elt->deleted) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } #ifdef __STDC__ Boolean local_undeleted_search(Mailbox *mailbox, Message_List *parent) #else Boolean local_undeleted_search(mailbox,parent) Mailbox *mailbox; Message_List *parent; #endif { Message_List *message_list; MESSAGECACHE *elt; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->longcache) { elt = &(message_list->message->longcache->elt); if(! elt->deleted) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } #ifdef __STDC__ Boolean local_flagged_search(Mailbox *mailbox, Message_List *parent) #else Boolean local_flagged_search(mailbox,parent) Mailbox *mailbox; Message_List *parent; #endif { Message_List *message_list; MESSAGECACHE *elt; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->longcache) { elt = &(message_list->message->longcache->elt); if(elt->flagged) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } #ifdef __STDC__ Boolean local_unflagged_search(Mailbox *mailbox, Message_List *parent) #else Boolean local_unflagged_search(mailbox,parent) Mailbox *mailbox; Message_List *parent; #endif { Message_List *message_list; MESSAGECACHE *elt; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->longcache) { elt = &(message_list->message->longcache->elt); if(! elt->flagged) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } #ifdef __STDC__ Boolean local_seen_search(Mailbox *mailbox, Message_List *parent) #else Boolean local_seen_search(mailbox,parent) Mailbox *mailbox; Message_List *parent; #endif { Message_List *message_list; MESSAGECACHE *elt; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->longcache) { elt = &(message_list->message->longcache->elt); if(elt->seen) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } #ifdef __STDC__ Boolean local_unseen_search(Mailbox *mailbox, Message_List *parent) #else Boolean local_unseen_search(mailbox,parent) Mailbox *mailbox; Message_List *parent; #endif { Message_List *message_list; MESSAGECACHE *elt; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->longcache) { elt = &(message_list->message->longcache->elt); if(! elt->seen) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } #ifdef __STDC__ Boolean local_answered_search(Mailbox *mailbox, Message_List *parent) #else Boolean local_answered_search(mailbox,parent) Mailbox *mailbox; Message_List *parent; #endif { Message_List *message_list; MESSAGECACHE *elt; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->longcache) { elt = &(message_list->message->longcache->elt); if(elt->answered) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } #ifdef __STDC__ Boolean local_unanswered_search(Mailbox *mailbox, Message_List *parent) #else Boolean local_unanswered_search(mailbox,parent) Mailbox *mailbox; Message_List *parent; #endif { Message_List *message_list; MESSAGECACHE *elt; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->longcache) { elt = &(message_list->message->longcache->elt); if(! elt->answered) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } #ifdef __STDC__ Boolean local_recent_search(Mailbox *mailbox, Message_List *parent) #else Boolean local_recent_search(mailbox,parent) Mailbox *mailbox; Message_List *parent; #endif { Message_List *message_list; MESSAGECACHE *elt; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->longcache) { elt = &(message_list->message->longcache->elt); if(elt->recent) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } #ifdef __STDC__ Boolean local_old_search(Mailbox *mailbox, Message_List *parent) #else Boolean local_old_search(mailbox,parent) Mailbox *mailbox; Message_List *parent; #endif { Message_List *message_list; MESSAGECACHE *elt; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->longcache) { elt = &(message_list->message->longcache->elt); if(! elt->recent) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } /* * Here we have the text searches: * SUBJECT * FROM * TEXT * BODY * HEADER * TO * CC * REPLY-TO * SENDER * MESSAGE-ID * IN-REPLY-TO * REPLY-TO * return-path * remail * > n if rfc822_size > n, then true ... */ #ifdef __STDC__ Boolean local_subject_search(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_subject_search(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { Message_List *message_list; char *subject; int len; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message) { subject = message_list->message->subject; if(subject) { len = strlen(subject); if((len) && (search(subject, len, pattern, strlen(pattern)))) mm_searched(mailbox->mailstream, message_list->message->msgno); } } } return TRUE; } #ifdef __STDC__ Boolean local_body_search(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_body_search(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { return(FALSE); } #ifdef __STDC__ Boolean local_header_search(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_header_search(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { return(FALSE); } #ifdef __STDC__ Boolean local_text_search(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_text_search(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { return(FALSE); } #ifdef __STDC__ Boolean local_msgid_search(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_msgid_search(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { Message_List *message_list; char *msgid; for(message_list = parent; message_list; message_list = message_list->next) { if((message_list->message) && (message_list->message->envelope)) { msgid = message_list->message->envelope->message_id; if((msgid) && (strlen(msgid)) && search(msgid,strlen(msgid),pattern,strlen(pattern))) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } #ifdef __STDC__ Boolean local_size_plus_grand_que(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_size_plus_grand_que(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { Message_List *message_list; MESSAGECACHE *elt; unsigned long size = (unsigned long) atol(pattern); for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->longcache) { elt = &(message_list->message->longcache->elt); if((elt) && (elt->rfc822_size > size)) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } #ifdef __STDC__ Boolean local_inreplyto_search(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_inreplyto_search(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { Message_List *message_list; char *in_reply_to; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->envelope) { in_reply_to = message_list->message->envelope->in_reply_to; if((in_reply_to) && (strlen(in_reply_to)) && search(in_reply_to,strlen(in_reply_to), pattern,strlen(pattern))) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } #ifdef __STDC__ Boolean local_on_search(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_on_search(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { Message_List *message_list; unsigned long date, msg_date; MESSAGECACHE *elt; MESSAGECACHE tmp_elt; if (!mail_parse_date (&tmp_elt, pattern)) return(FALSE); date = (tmp_elt.year << 9) + (tmp_elt.month << 5) + tmp_elt.day; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->longcache) { elt = &(message_list->message->longcache->elt); msg_date = (elt->year << 9) + (elt->month << 5) + elt->day; if (msg_date == date) /* message on the date */ mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } #ifdef __STDC__ Boolean local_since_search(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_since_search(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { Message_List *message_list; unsigned long date, msg_date; MESSAGECACHE *elt; MESSAGECACHE tmp_elt; if (!mail_parse_date (&tmp_elt, pattern)) return(TRUE); date = (tmp_elt.year << 9) + (tmp_elt.month << 5) + tmp_elt.day; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->longcache) { elt = &(message_list->message->longcache->elt); msg_date = (elt->year << 9) + (elt->month << 5) + elt->day; if (msg_date >= date) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } #ifdef __STDC__ Boolean local_before_search(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_before_search(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { Message_List *message_list; unsigned long date, msg_date; MESSAGECACHE *elt; MESSAGECACHE tmp_elt; if (!mail_parse_date (&tmp_elt, pattern)) return(TRUE); date = (tmp_elt.year << 9) + (tmp_elt.month << 5) + tmp_elt.day; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->longcache) { elt = &(message_list->message->longcache->elt); msg_date = (elt->year << 9) + (elt->month << 5) + elt->day; if (msg_date < date) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return TRUE; } #ifdef __STDC__ Boolean local_from_search(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_from_search(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { Message_List *message_list; char addr[FILEBUFFLEN]; ADDRESS *base; int len; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->envelope) { base = message_list->message->envelope->from; local_make_addr_str(base,addr); len = strlen(addr); if((len) && (search(addr,len,pattern,strlen(pattern)))) mm_searched(mailbox->mailstream, message_list->message->msgno); } } return(TRUE); } #ifdef __STDC__ Boolean local_to_search(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_to_search(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { Message_List *message_list; char addr[FILEBUFFLEN]; ADDRESS *base; int len; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->envelope) { base = message_list->message->envelope->to; while(base) { local_make_addr_str(base,addr); len = strlen(addr); if((len) && (search(addr,len,pattern,strlen(pattern)))) { mm_searched(mailbox->mailstream, message_list->message->msgno); break; } else base = base->next; } } } return(TRUE); } #ifdef __STDC__ Boolean local_cc_search(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_cc_search(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { Message_List *message_list; char addr[FILEBUFFLEN]; ADDRESS *base; int len; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->envelope) { base = message_list->message->envelope->cc; while(base) { local_make_addr_str(base,addr); len = strlen(addr); if((len) && (search(addr,len,pattern,strlen(pattern)))) { mm_searched(mailbox->mailstream, message_list->message->msgno); break; } else base = base->next; } } } return(TRUE); } #ifdef __STDC__ Boolean local_reply_to_search(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_reply_to_search(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { Message_List *message_list; char addr[FILEBUFFLEN]; ADDRESS *base; int len; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->envelope) { base = message_list->message->envelope->reply_to; while(base) { local_make_addr_str(base,addr); len = strlen(addr); if((len) && (search(addr,len,pattern,strlen(pattern)))) { mm_searched(mailbox->mailstream, message_list->message->msgno); break; } else base = base->next; } } } return(TRUE); } #ifdef __STDC__ Boolean local_sender_search(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_sender_search(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { Message_List *message_list; char addr[FILEBUFFLEN]; ADDRESS *base; int len; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->envelope) { base = message_list->message->envelope->sender; while(base) { local_make_addr_str(base,addr); len = strlen(addr); if((len) && (search(addr,len,pattern,strlen(pattern)))) { mm_searched(mailbox->mailstream, message_list->message->msgno); break; } else base = base->next; } } } return(TRUE); } #ifdef __STDC__ Boolean local_replyto_search(Mailbox *mailbox, Message_List *parent, char *pattern) #else Boolean local_replyto_search(mailbox,parent,pattern) Mailbox *mailbox; Message_List *parent; char *pattern; #endif { Message_List *message_list; char addr[FILEBUFFLEN]; ADDRESS *base; int len; for(message_list = parent; message_list; message_list = message_list->next) { if(message_list->message && message_list->message->envelope) { base = message_list->message->envelope->reply_to; while(base) { local_make_addr_str(base,addr); len = strlen(addr); if((len) && (search(addr,len,pattern,strlen(pattern)))) { mm_searched(mailbox->mailstream, message_list->message->msgno); break; } else base = base->next; } } } return(TRUE); } /* * IF the predicate type requires a dynamic field, ie, one whose * value is set at search time, then set its value. We remake the * predicate/field pair, and return it to be used in search */ DYNAMIC dynamic_table[]= { { NULL, XtNfilterToday, "TODAY", set_today }, { NULL, XtNfilterYesterday, "YESTERDAY", set_hier }, { NULL, XtNfilterLastMonth, "LASTMONTH", set_mois_dernier }, { NULL, XtNfilterThisMonth, "THISMONTH", set_mois_courant }, { NULL, XtNfilterJanuary, "JANUARY", set_january }, { NULL, XtNfilterFebruary, "FEBRUARY", set_february }, { NULL, XtNfilterMarch, "MARCH", set_march }, { NULL, XtNfilterApril, "APRIL", set_april }, { NULL, XtNfilterMay, "MAY", set_may }, { NULL, XtNfilterJune, "JUNE", set_june }, { NULL, XtNfilterJuly, "JULY", set_july }, { NULL, XtNfilterAugust, "AUGUST", set_august }, { NULL, XtNfilterSeptember, "SEPTEMBER", set_september }, { NULL, XtNfilterOctober, "OCTOBER", set_october }, { NULL, XtNfilterNovember, "NOVEMBER", set_november }, { NULL, XtNfilterDecember, "DECEMBER", set_december }, { NULL, XtNfilterSunday, "SUNDAY", set_sunday }, { NULL, XtNfilterMonday, "MONDAY", set_monday }, { NULL, XtNfilterTuesday, "TUESDAY", set_tuesday }, { NULL, XtNfilterWednesday, "WEDNESDAY", set_wednesday }, { NULL, XtNfilterThursday, "THURSDAY", set_thursday }, { NULL, XtNfilterFriday, "FRIDAY", set_friday }, { NULL, XtNfilterSaturday, "SATURDAY", set_saturday }, { NULL, XtNfilterLastSunday, "LASTSUNDAY", set_lastsunday }, { NULL, XtNfilterLastMonday, "LASTMONDAY", set_lastmonday }, { NULL, XtNfilterLastTuesday, "LASTTUESDAY", set_lasttuesday }, { NULL, XtNfilterLastWednesday, "LASTWEDNESDAY", set_lastwednesday }, { NULL, XtNfilterLastThursday, "LASTTHURSDAY", set_lastthursday }, { NULL, XtNfilterLastFriday, "LASTFRIDAY", set_lastfriday }, { NULL, XtNfilterLastSaturday, "LASTSATURDAY", set_lastsaturday }, { NULL, NULL, NULL, NULL } }; /* Simple search dispatchers (no args). */ SEARCHERS local_chercheurs_simple[]= { { "NEW", local_new_search }, { "OLD", local_old_search }, { "DELETED", local_deleted_search }, { "UNDELETED", local_undeleted_search }, { "SEEN", local_seen_search }, { "UNSEEN", local_unseen_search }, { "RECENT", local_recent_search }, { "ANSWERED", local_answered_search }, { "UNANSWERED", local_unanswered_search }, { "FLAGGED", local_flagged_search }, { "UNFLAGGED", local_unflagged_search }, { NULL, NULL } }; /* These require a search pattern */ SEARCHERS local_chercheurs_grands[] = { { "SUBJECT", local_subject_search }, { "FROM", local_from_search }, { "TO", local_to_search }, { "CC", local_cc_search }, { "ON", local_on_search }, { "SINCE", local_since_search }, { "BEFORE", local_before_search }, { "MESSAGE-ID", local_msgid_search }, { "SENDER", local_sender_search }, { "IN-REPLY-TO", local_inreplyto_search }, { "LARGER", local_size_plus_grand_que }, { "HEADER", local_header_search }, { "TEXT", local_text_search }, { "BODY", local_body_search }, { NULL, NULL } }; #ifdef __STDC__ char *update_dynamic_predicates(LEAF *leaf) #else char *update_dynamic_predicates(leaf) LEAF *leaf; #endif { char tmp[FILEBUFFLEN]; char unquoted[FILEBUFFLEN]; char *field; char *dynamic_value; DYNAMIC *dyn; int len; char *nouveau; if (leaf->predicate_type != pred_dynamic_field) return NULL; /* Isolate the field */ field = strchr(leaf->predicate,(int) SPACECHAR) + 1; if(*field == DQUOTECHAR) field ++; strcpy(unquoted,field); if(unquoted[strlen(unquoted) - 1] == DQUOTECHAR) unquoted[strlen(unquoted) - 1] = NUL_TERM; /* dispatch on field value */ for (dynamic_value = NULL, dyn = dynamic_table; dyn->value; ++dyn) { if (strcasecmp(unquoted, dyn->localized) == STRMATCH) { dynamic_value = (*dyn->set_dynamic)(); break; } } if (!dynamic_value) { /* Dynamic values NOT required in dynamic fields */ return NULL; } /* * Remake predicate with dynamic value and protocol verb (not localized). */ strcpy(tmp, leaf->predicate); strtok(tmp, " "); /* NULL terminate predicate */ len = strlen(tmp) + strlen(dynamic_value) + 2; /* SPACE and NULL too */ nouveau = (char *)fs_get(len); sprintf(nouveau, "%s %s", tmp, dynamic_value); return nouveau; } /* * The dispatcher */ #ifdef __STDC__ void local_select_field(char *str, char *obuf) #else void local_select_field(str, obuf) char *str; char *obuf; #endif { /* clear any leading SPACES */ while (*str == SPACECHAR) ++str; /* Now a possibly leading \" */ if (*str && *str == DQUOTECHAR) ++str; /* copy the rest into out output buffer */ strcpy(obuf, str); /* now step on the last " */ if(obuf[strlen(obuf) - 1] == DQUOTECHAR) obuf[strlen(obuf) - 1] = NUL_TERM; return; } #ifdef __STDC__ Boolean local_search(Mailbox *mailbox, Lview *lview, char *predicate) #else Boolean local_search(mailbox, lview, predicate) Mailbox *mailbox; Lview *lview; char *predicate; #endif { char token[PARSEBUFLEN]; char field[PARSEBUFLEN]; char *chemise= token; SEARCHERS *chs; SEARCHERS *gchs; /* strip off the chemise */ while (*predicate && *predicate != SPACECHAR) *chemise++ = *predicate++; *chemise = NUL_TERM; /* OK, find the local chercheur */ for (chs = local_chercheurs_simple; chs->token; ++chs) { if (strcasecmp(chs->token, token) == STRMATCH) { return (*chs->chercheur)(mailbox, lview->message_list); } } for (gchs = local_chercheurs_grands; gchs->token; ++gchs) { if (strcasecmp(gchs->token, token) == STRMATCH) { local_select_field(predicate, field); return (*gchs->chercheur)(mailbox, lview->message_list, field); } } return FALSE; } /* Action parsing routines and tables. */ ACTIONREC actlist[] = { { "delete", NULL, XtNactionDelete, DELETE_ACT, FALSE, FALSE, TRUE }, { "expunge", NULL, XtNactionExpunge, EXPUNGE_ACT, FALSE, FALSE, TRUE }, { "copy", NULL, XtNactionCopy, COPY_ACT, FALSE, TRUE, TRUE }, { "move", NULL, XtNactionMove, MOVE_ACT, FALSE, TRUE, TRUE }, { "save", NULL, XtNactionSave, SAVE_ACT, TRUE, TRUE, TRUE }, { "shell", NULL, XtNactionShell, SHELL_ACT, TRUE, TRUE, TRUE }, { "flag", NULL, XtNactionFlag, FLAG_ACT, FALSE, FALSE, TRUE }, { "set", NULL, XtNactionSet, SET_ACT, FALSE, TRUE, TRUE }, { "unset", NULL, XtNactionUnset, UNSET_ACT, FALSE, TRUE, TRUE }, { "reply", NULL, XtNactionReply, REPLY_ACT, FALSE, TRUE, FALSE }, { "print", NULL, XtNactionPrint, PRINT_ACT, TRUE, FALSE, TRUE }, { "select", NULL, XtNactionSelect, SELECT_ACT, FALSE, FALSE, TRUE }, { "new", NULL, XtNactionNew, NEW_ACT, FALSE, FALSE, TRUE }, { "unseen", NULL, XtNactionUnseen, UNSEEN_ACT, FALSE, FALSE, TRUE }, { "unselect", NULL, XtNactionUnselect, UNSELECT_ACT, FALSE, FALSE, TRUE }, { "read", NULL, XtNactionRead, READ_ACT, FALSE, FALSE, TRUE }, { NULL, NULL, NULL, NO_ACT, FALSE, FALSE, FALSE } }; HEADERREC hdrlist[] = { { "noheader", NULL, XtNactionNoHeader, HEADER_NONE }, { "partheader", NULL, XtNactionPartHeader, HEADER_PART }, { "fullheader", NULL, XtNactionFullHeader, HEADER_FULL }, { NULL, NULL, NULL, HEADER_UNKNOWN } }; #ifdef __STDC__ void init_action_and_header_list(void) #else void init_action_and_header_list() #endif { int i; for(i = 0; actlist[i].name != NULL; i ++ ) actlist[i].localized = MLGetLocalized(actlist[i].resource,actlist[i].name); for(i = 0; hdrlist[i].name != NULL; i ++) hdrlist[i].localized = MLGetLocalized(hdrlist[i].resource,hdrlist[i].name); return; } #ifdef __STDC__ ACTIONREC *find_action(char *s) #else ACTIONREC *find_action(s) char *s; #endif { ACTIONREC *a; for(a = actlist; (a->name != NULL); a ++ ) { if(strncasecmp(s,a->localized,strlen(a->localized)) == 0) return(a); } return(NULL); } #ifdef __STDC__ HEADERREC *get_hdrlist(char *s) #else HEADERREC *get_hdrlist(s) char *s; #endif { HEADERREC *h; for(h = hdrlist; (h->name != NULL); h ++ ) { if(strncasecmp(s,h->localized,strlen(h->localized)) == 0) return(h); } return(NULL); } #ifdef __STDC__ void free_actions(char **ss) #else void free_actions(ss) char ** ss; #endif { int n; for(n = 0; ss[n] != NULL; n ++) fs_give((void **) &(ss[n])); fs_give((void **) ss); return; } #ifdef __STDC__ char **get_actions(char *s) #else char **get_actions(s) char *s; #endif { int len, n; char *ptr = s; char *endptr; char *zeroptr; char **ret = NULL; char buf[FILEBUFFLEN]; len = count_separators(s); if(!len) return(NULL); ret = (char **) fs_get((len + 1) * sizeof(char *)); n = 0; while(*ptr != NUL_TERM) { while(isspace(*((unsigned char *)ptr))) ptr ++; endptr = strchr(ptr,ACTION_SEPARATOR); if(endptr == NULL) break; strncpy(buf,ptr,(int) (endptr - ptr)); buf[endptr-ptr] = NUL_TERM; for(zeroptr = &buf[strlen(buf)-1]; (isspace(*((unsigned char *)zeroptr))); zeroptr --) *zeroptr = NUL_TERM; if(! strlen(buf)) break; ret[n] = cpystr(buf); n ++; ptr = (++endptr); } ret[n] = NULL; return(ret); } #ifdef __STDC__ int count_separators(char *s) #else int count_separators(s) char *s; #endif { int n = 0; char *p; for(p = s; (*p) ; p ++ ) if(*p == ACTION_SEPARATOR) n ++; return(n); } /* Warning: we dispose of the calling string in this call */ #ifdef __STDC__ char *clean_and_parse_action(char *s) #else char *clean_and_parse_action(s) char *s; #endif { char buffer[FILEBUFFLEN]; char warn[FILEBUFFLEN]; char *ptr = s; char *ret = NULL; char *end_of_arg = NULL; int errors = 0; char *qptr = NULL; ACTIONREC *a = NULL; HEADERREC *h = NULL; *buffer = NUL_TERM; while(*ptr) { while(isspace(*((unsigned char *) ptr))) ptr ++; a = find_action(ptr); if(a == NULL || a->implemented == FALSE) { if(strlen(ptr)) { end_of_arg = strpbrk(ptr," \t\n;"); if(end_of_arg) *end_of_arg = NUL_TERM; sprintf(warn,MLGetLocalized(XtNmsgUnknownAction,MsgUnknownAction),ptr); mm_log(warn,WARN); errors ++; } buffer[strlen(buffer)] = NUL_TERM; break; } else { ptr += strlen(a->localized); strcat(buffer,a->localized); strcat(buffer,SPACESTR); if( a->arg == FALSE && a->option == FALSE ) { ptr = strchr(ptr,(int) ACTION_SEPARATOR); if(ptr) { strcat(buffer,"; "); ptr ++; continue; } else { strcat(buffer, "; "); break; } } if(a->option == TRUE ) { while(isspace(*((unsigned char *)ptr))) ptr ++; h = get_hdrlist(ptr); if(h) { ptr += strlen(h->localized); strcat(buffer,h->localized); strcat(buffer,SPACESTR); } else { strcat(buffer,hdrlist[HEADER_PART].localized); strcat(buffer,SPACESTR); } } if(a->arg == FALSE) { ptr = strchr(ptr,(int) ACTION_SEPARATOR); if(ptr) { strcat(buffer,"; "); ptr ++; continue; } else { strcat(buffer, "; "); break; } } while(isspace(*((unsigned char *)ptr))) ptr ++; if((! *ptr) || (*ptr == ACTION_SEPARATOR)) { sprintf(warn,MLGetLocalized(XtNmsgActionRequiresArg, MsgActionRequiresArg),a->localized); mm_log(warn,WARN); errors ++; break; } if(*ptr == DQUOTECHAR) { qptr = strchr(ptr+1, DQUOTECHAR); if(! qptr) { mm_log(MLGetLocalized(XtNmsgMissingQuote,MsgMissingQuote),WARN); errors ++; break; } end_of_arg = strpbrk(qptr," \t\n;"); } else end_of_arg = strpbrk(ptr," \t\n;"); if(! end_of_arg) { strcat(buffer,(char *)ptr); strcat(buffer," ; "); break; } else { strncat(buffer,ptr,(int) (end_of_arg - ptr)); strcat(buffer," ; "); ptr = end_of_arg; while((isspace(*((unsigned char *)ptr))) || (*ptr == ACTION_SEPARATOR)) ptr ++; continue; } } } fs_give((void **) &s); if(errors) { ret = cpystr(EMPTYSTR); return(ret); } if(strlen(buffer)) ret = cpystr(buffer); else ret = cpystr(EMPTYSTR); return(ret); } /* Filter parsing routines and tables. */ static STOKEN search_tokens[]= { { NULL, XtNfilterTo, "TO", /* Token string */ TRUE, /* True if field required */ STRSEARCH, }, /* search type: local / server */ { NULL, XtNfilterFrom, "FROM", TRUE, STRSEARCH, }, { NULL, XtNfilterCc, "CC", TRUE, STRSEARCH, }, { NULL, XtNfilterCorrespondent, CORRESPONDENT_MACRO, TRUE, STRSEARCH, }, { NULL, XtNfilterRecipient, RECIPIENT_MACRO, TRUE, STRSEARCH, }, { NULL, XtNfilterConversant, CONVERSANT_MACRO, TRUE, STRSEARCH, }, { NULL, XtNfilterSubject, "SUBJECT", TRUE, STRSEARCH, }, { NULL, XtNfilterText, "TEXT", TRUE, STRSEARCH, }, { NULL, XtNfilterHeader, "HEADER", TRUE, STRSEARCH, }, { NULL, XtNfilterBody, "BODY", TRUE, STRSEARCH, }, { NULL, XtNfilterMessageId, "MESSAGE-ID", TRUE, STRSEARCH, }, { NULL, XtNfilterSender, "SENDER", TRUE, STRSEARCH, }, { NULL, XtNfilterReplyTo, "REPLY-TO", TRUE, STRSEARCH, }, { NULL, XtNfilterInReplyTo, "IN-REPLY-TO", TRUE, STRSEARCH, }, { NULL, XtNfilterSince, "SINCE", TRUE, TIMESEARCH, /* TIME attribute */ }, { NULL, XtNfilterBefore, "BEFORE", TRUE, TIMESEARCH, }, { NULL, XtNfilterOn, "ON", TRUE, TIMESEARCH, }, { NULL, XtNfilterLarger, "LARGER", TRUE, ATOMIC+NUMERIC, }, { NULL, XtNfilterNew, "NEW", FALSE, NONE, }, { NULL, XtNfilterOld, "OLD", FALSE, NONE, }, { NULL, XtNfilterDeleted, "DELETED", FALSE, NONE, }, { NULL, XtNfilterUndeleted, "UNDELETED", FALSE, NONE, }, { NULL, XtNfilterSeen, "SEEN", FALSE, NONE, }, { NULL, XtNfilterUnseen, "UNSEEN", FALSE, NONE, }, { NULL, XtNfilterRecent, "RECENT", FALSE, NONE, }, { NULL, XtNfilterAnswered, "ANSWERED", FALSE, NONE, }, { NULL, XtNfilterUnanswered, "UNANSWERED", FALSE, NONE, }, { NULL, XtNfilterFlagged, "FLAGGED", FALSE, NONE, }, { NULL, XtNfilterUnflagged, "UNFLAGGED", FALSE, NONE, }, { NULL, NULL, NULL, FALSE, NONE, } }; BOOLEAN_LIST boolean_tokens[]= { { NULL, XtNfilterAnd, "AND", AND_OP }, { NULL, XtNfilterOr, "OR", OR_OP }, { NULL, XtNfilterNot, "NOT", NOT_OP }, { NULL, NULL, NULL, NO_OP } }; #ifdef __STDC__ void init_logical_view_structures(void) #else void init_logical_view_structures() #endif { int i; for(i = 0; search_tokens[i].token != NULL; i ++) search_tokens[i].localized = MLGetLocalized(search_tokens[i].resource, search_tokens[i].token); for(i = 0; dynamic_table[i].value != NULL; i ++) dynamic_table[i].localized = MLGetLocalized(dynamic_table[i].resource, dynamic_table[i].value); for(i = 0; boolean_tokens[i].operator != NULL; i ++) boolean_tokens[i].localized = MLGetLocalized(boolean_tokens[i].resource, boolean_tokens[i].operator); } /* return pointer to last char in a string */ #ifdef __STDC__ char *last(char *str) #else char *last(str) char *str; #endif { int len = strlen(str); return &str[len - 1]; } /* Match str to a token in tlist. * Return a STOKEN pointer, or NULL */ #ifdef __STDC__ STOKEN * found_token(STOKEN *tlist, char *token, parse_errors *err) #else STOKEN * found_token(tlist, token, err) STOKEN *tlist; char *token; parse_errors *err; #endif { int i; for (i = 0; tlist[i].token; ++i) if (strcasecmp(token, tlist[i].localized) == STRMATCH) return &tlist[i]; *err = illegal_token; return NULL; } #ifdef __STDC__ BOOLEAN_OPERATOR found_boolean(BOOLEAN_LIST *blist, char *str) #else BOOLEAN_OPERATOR found_boolean(blist, str) BOOLEAN_LIST *blist; char *str; #endif { int i; for (i = 0; boolean_tokens[i].operator; ++i) if (strcasecmp(str, boolean_tokens[i].localized) == STRMATCH) { return boolean_tokens[i].boole; } return NO_OP; } #ifdef __STDC__ char *make_predicate(char *token, char *field, Boolean needs_field, unsigned long attributes) #else char *make_predicate(token, field, needs_field, attributes) char *token, *field; Boolean needs_field; unsigned long attributes; #endif { int len; char *string = NULL; Boolean quoted; if (needs_field == FALSE) return(cpystr(token)); len = strlen(token) + strlen(field) + 8; string = (char *) fs_get(len); quoted = (*field == DQUOTECHAR); if ((quoted == TRUE) || (attributes & ATOMIC)) sprintf(string,"%s %s", token, field); else sprintf(string,"%s \"%s\"", token, field); return string; } /* place null at end of field, and return pointer to beginnig of the field. n_excess will count surrounding parenthesis and any whitespace we step on to terminate the field .*/ #ifdef __STDC__ char *set_form_end(char *field, int *n_excess, parse_errors *err) #else char *set_form_end(field, n_excess, err) char *field; int *n_excess; parse_errors *err; #endif { char c, *cp= field, *cp0= field; *n_excess = 0; if (*cp == DQUOTECHAR) { /* search for '"' */ ++cp; /* skip initial '"' */ while ((c = *cp++) != NUL_TERM) { if (c == DQUOTECHAR) { *cp = NUL_TERM; /* tie it off */ return cp0; /* found our matching " */ } } /* * We should never reach this error because "" parsing is done * before we parse for structure detail */ *err = missing_dquote; return NULL; /* This should never happen */ } /* OK, search for whitespace or a terminating ')' */ while ((c = *cp) != NUL_TERM) { if ((c == SPACECHAR) || (c == TABCHAR)) { *cp = NUL_TERM; /* tie it off */ ++n_excess; /* stepped on white-space */ } ++cp; } return cp0; } #ifdef __STDC__ Boolean numeric_field(char *field, parse_errors *err) #else Boolean numeric_field(field, err) char *field; parse_errors *err; #endif { int i; if (*field == '\"') ++field; i = atoi(field); if (i <= 0) { *err = illegal_numeric_field; return FALSE; } return TRUE; } #ifdef __STDC__ Boolean select_field(char **fptr, STOKEN *tptr, char *field, int *len_trouve, parse_errors *err) #else Boolean select_field(fptr, tptr, field, len_trouve, err) char **fptr; STOKEN *tptr; char *field; int *len_trouve; parse_errors *err; #endif { char c; int loc_len= 0; char *loc_str, *str= field; /* Anything left? */ if (!*field) { *err = missing_field; return FALSE; } loc_str = set_form_end(str, &loc_len, err); if (!loc_str) return FALSE; /* Is it a \". Note that any surrounding parenthesis have already been counted in set_form_end(). */ if (*loc_str == DQUOTECHAR) { /* quoted field */ ++loc_str; loc_len += 1; while (((c = *loc_str++)) != NUL_TERM) { /* cherche '"' termination */ loc_len += 1; if (c == DQUOTECHAR) { *len_trouve = loc_len; *fptr = str; return TRUE; } } *err = missing_dquote; return FALSE; } /* Take next variable, ie, break on white-space or end-of-string */ while (((c = *loc_str++)) != NUL_TERM) if ((c == SPACECHAR) || (c == TABCHAR)) break; else loc_len += 1; *len_trouve = loc_len; *fptr = str; return TRUE; } #ifdef __STDC__ int fix_whitespace(char *str) #else int fix_whitespace(str) char *str; #endif { char *src, *dst; char c; int ws= 1; /* to clear leading whitespace */ src = dst = str; /* Compact all whitespace */ while (((c = *src++)) != NUL_TERM) { if (c == LFCHAR) continue; /* skip RETURN */ if ((c == SPACECHAR) || (c == TABCHAR)) { ws += 1; /* count whitespace */ if (ws > 1) continue; /* skip it */ c = SPACECHAR; /* use SPACE */ } else ws = 0; *dst++ = c; } *dst = NUL_TERM; } /* refuse blank names */ #ifdef __STDC__ Boolean whitespace_name(char *str) #else Boolean whitespace_name(str) char *str; #endif { char c; while (((c = *str++)) != NUL_TERM) if ((c != SPACECHAR) && (c != TABCHAR)) return FALSE; return TRUE; } /* * add a new leaf to our tree. */ #ifdef __STDC__ void add_leaf_to_tree(LEAF **root, char *ctoken, char *cfield, BOOLEAN_OPERATOR operator, STOKEN *tptr, Boolean found_not) #else void add_leaf_to_tree(root, ctoken, cfield, operator, tptr, found_not) LEAF **root; char *ctoken; char *cfield; BOOLEAN_OPERATOR operator; STOKEN *tptr; Boolean found_not; #endif { LEAF *leaf = (LEAF *) fs_get(sizeof(LEAF)); LEAF *prev; leaf->predicate = make_predicate(ctoken, cfield, tptr->field_required, tptr->field_attributes); leaf->operator = operator; leaf->atomic_not = found_not; leaf->predicate_type = (tptr->field_required ? pred_field : pred_simple); /* some predicate fields are dynamic at search time */ if ((leaf->predicate_type == pred_field) && (tptr->field_attributes & TIMESEARCH)) leaf->predicate_type = pred_dynamic_field; /* Adjoin the leaf to the tree */ if (*root == NULL) *root = leaf; else { for(prev = *root; prev->next; prev = prev->next) ; prev->next = leaf; } leaf->next = NULL; } /* * dispose of the tree */ #ifdef __STDC__ void cut_down_the_tree(LEAF *leafs) #else void cut_down_the_tree(leafs) LEAF *leafs; #endif { LEAF *feuille; /* dispose of the tree */ while (leafs) { feuille = leafs; fs_give((void **) &feuille->predicate); /* the string */ leafs = feuille->next; /* next leaf */ fs_give((void **) &feuille); /* the structure */ } } /* * create IMAP search filter from the tree's leaf's */ #ifdef __STDC__ void move_leafs_to_filter(LEAF **search_tree, char **search_text, LEAF *leafs, char *text) #else void move_leafs_to_filter(search_tree, search_text, leafs, text) LEAF **search_tree; char **search_text; LEAF *leafs; char *text; #endif { /* the search_filter.name is set up by the caller to lv_parse_filter */ *search_tree = leafs; *search_text = text; } /* augment the filter by len */ #ifdef __STDC__ char *advance_filter(char *filter, int *filter_len, int len) #else char *advance_filter(filter, filter_len, len) char *filter; int *filter_len; int len; #endif { *filter_len -= len; /* decrement by string length */ if (*filter_len > 1) { filter += len + 1; /* next list item */ *filter_len -= 1; /* advance one char more */ } else filter += len; /* points to NULL termination */ return filter; } /* * Here we parse the filter text provided by the user * Returns: parse_success if parse does not fail. Otherwise an ERROR */ #define TOKEN_STOPS " \t" #define ERRMSGLEN 32 #ifdef __STDC__ parse_errors lv_parse_filter(char *name_text, char *filter_text, LEAF **search_tree, char **search_text, char *errmsg) #else parse_errors lv_parse_filter(name_text, filter_text, search_tree, search_text, errmsg) char *name_text; char *filter_text; LEAF **search_tree; char **search_text; char *errmsg; #endif { char *search_string; /* destination */ STOKEN *tokens= search_tokens; /* our tokens */ char *filter= filter_text; /* source to parse */ char *ctoken; /* current token */ STOKEN *tptr; /* token block */ char *field; /* for a field */ int filter_len; /* chars in filter */ int field_len; int other_len; parse_errors err, rval; /* in places, used for error return */ BOOLEAN_OPERATOR operator = NO_OP; /* AND_OP / OR_OP / NO_OP */ BOOLEAN_OPERATOR not_op = NO_OP; LEAF *arbe= NULL; /* the tree which grows on C street */ int next_term= TOKEN; /* initially a TOKEN */ int parsing; /* counts terms */ Boolean looping= TRUE; /* keeps it going */ Boolean found_not = FALSE; char *ptr0; char *ptr9; /* Make sure the name is not white-space */ if (whitespace_name(name_text)) { return invalid_name; } fix_whitespace(filter); /* clear unnecessary whitespace */ filter_len = strlen(filter); /* what's is there */ operator = NO_OP; search_string = cpystr(filter); /* save a copy */ *errmsg = NUL_TERM; /* no message yet */ strcpy(errmsg, MLGetLocalized(XtNmsgFilterParseError, MsgFilterParseError)); /* Main parse loop... */ for (parsing = 0; looping; ++parsing) { /* * Here we expect to find a predicate like "FROM" or "DELETED" */ ptr0 = filter; if(*ptr0 == DQUOTECHAR) { ptr0 ++; while (*ptr0 && *ptr0 != DQUOTECHAR) ptr0 ++; } ptr9 = strpbrk(ptr0, TOKEN_STOPS); if(ptr9) *ptr9 = NUL_TERM; ctoken = filter; if(*ctoken == NUL_TERM) ctoken = NULL; /* !@#$%^&*()#%@&^% strtok! */ /*ctoken = strtok(filter, TOKEN_STOPS); first token */ if (!ctoken) { if (parsing == 0) { /* First time through */ err = empty_filter; /* no filter provided */ } else if (next_term == GEORGES_BOOLE) { /* Final term a predicate */ err = no_error; } else err = missing_predicate; /* No predicate after AND/OR */ break; } /* check for token or Boolean operator */ switch (next_term) { case TOKEN: /* First check for NOT. It's a boolean, but will be located here. */ not_op = found_boolean(boolean_tokens, ctoken); if (not_op == NOT_OP) { found_not = TRUE; other_len = strlen(ctoken); filter = advance_filter(filter, &filter_len, other_len); ptr0 = filter; if(*ptr0 == DQUOTECHAR) { ptr0 ++; while (*ptr0 && *ptr0 != DQUOTECHAR) ptr0 ++; } ptr9 = strpbrk(ptr0, TOKEN_STOPS); if(ptr9) *ptr9 = NUL_TERM; ctoken = filter; if(*ctoken == NUL_TERM) ctoken = NULL; /* !@#$%^&*()#%@&^% strtok! */ /* ctoken = strtok(filter, TOKEN_STOPS); first token */ } else found_not = FALSE; /* select a token from our tokens[] */ if ((tptr = found_token(tokens, ctoken, &err)) == NULL) { looping = FALSE; strcat(errmsg, ctoken); continue; } else { other_len = strlen(ctoken); /* includes parenthesis, not */ next_term = GEORGES_BOOLE; /* Boolean next en haut.*/ } filter = advance_filter(filter, &filter_len, other_len); break; case GEORGES_BOOLE: /* * We find the operator which binds the NEXT predicate with * it predecessors */ operator = found_boolean(boolean_tokens, ctoken); if ((operator == NO_OP) || (operator == NOT_OP)) { err = expected_boolean; looping = FALSE; strcat(errmsg, ctoken); continue; } else { other_len = strlen(ctoken); next_term = TOKEN; /* token on next pass */ } filter = advance_filter(filter, &filter_len, other_len); continue; } /* check for */ if (tptr->field_required) { if (!select_field(&field, tptr, filter, &field_len, &err)) { looping = FALSE; /* err set in select_field */ strcat(errmsg, ctoken); continue; } if (tptr->field_attributes & NUMERIC && !numeric_field(field, &err)) { looping = FALSE; strcat(errmsg, field); continue; } filter_len -= field_len; /* decrement chars remaining */ filter += field_len; /* skip field in string */ *filter = '\0'; /* terminate predicate */ if (filter_len > 0) { /* then not at end */ ++filter; /* to next term */ --filter_len; /* one less character */ } } else { field = ""; /* No field - filter is OK. */ } /* place in our parsing tree */ add_leaf_to_tree(&arbe, ctoken, field, operator, tptr, found_not); } /* * chase down the tree and build the various search filters */ if (err == no_error) { move_leafs_to_filter(search_tree, search_text, arbe, search_string); rval = parse_success; } else { cut_down_the_tree(arbe); /* dispose of the tree */ fs_give((void **) &search_string); /* And the string */ rval = err; } return rval; }