From 44ab8b1fd0e0386b15fd9c54f366ba1977e693c2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Wilfried=20G=C3=B6esgens?= Date: Sun, 30 Nov 2008 23:10:52 +0000 Subject: [PATCH] * abstract sorting algorithms. abstraction layer so far used in the message view. * reorder subst.c so related functions are next to each other * remove array from WC, its done through the hash... --- webcit/calendar.c | 8 - webcit/messages.c | 679 ++++++++------------------ webcit/msg_renderers.c | 132 ++++- webcit/rss.c | 21 +- webcit/smtpqueue.c | 8 +- webcit/subst.c | 1046 ++++++++++++++++++++++++++-------------- webcit/webcit.h | 11 +- webcit/webserver.c | 2 + 8 files changed, 1040 insertions(+), 867 deletions(-) diff --git a/webcit/calendar.c b/webcit/calendar.c index 15f333bfa..33864203e 100644 --- a/webcit/calendar.c +++ b/webcit/calendar.c @@ -374,14 +374,6 @@ void handle_rsvp(void) -int Flathash(const char *str, long len) -{ - if (len != sizeof (int)) - return 0; - else return *(int*)str; -} - - /* * free memory allocated using libical diff --git a/webcit/messages.c b/webcit/messages.c index 49aa1c696..38f4a4b19 100644 --- a/webcit/messages.c +++ b/webcit/messages.c @@ -35,190 +35,8 @@ typedef void (*MsgPartEvaluatorFunc)(message_summary *Sum, StrBuf *Buf); -const char* SortIcons[3] = { - "static/up_pointer.gif", - "static/down_pointer.gif", - "static/sort_none.gif" -}; - -enum {/// SortByEnum - eDate, - eRDate, - eSubject, - eRSubject, - eSender, - eRSender, - eReverse, - eUnSet -}; - -/* SortEnum to plain string representation */ -static const char* SortByStrings[] = { - "date", - "rdate", - "subject", - "rsubject", - "sender", - "rsender", - "reverse", - "unset" -}; - -/* SortEnum to sort-Function Table */ -const CompareFunc SortFuncs[eUnSet] = { - summcmp_date, - summcmp_rdate, - summcmp_subj, - summcmp_rsubj, - summcmp_sender, - summcmp_rsender, - summcmp_rdate -}; - -/* given a SortEnum, which icon should we choose? */ -const int SortDateToIcon[eUnSet] = { eUp, eDown, eNone, eNone, eNone, eNone, eNone}; -const int SortSubjectToIcon[eUnSet] = { eNone, eNone, eUp, eDown, eNone, eNone, eNone}; -const int SortSenderToIcon[eUnSet] = { eNone, eNone, eNone, eNone, eUp, eDown, eNone}; - -/* given a SortEnum, which would be the "opposite" search option? */ -const int DateInvertSortString[eUnSet] = { eRDate, eDate, eDate, eDate, eDate, eDate, eDate}; -const int SubjectInvertSortString[eUnSet] = { eSubject, eSubject, eRSubject, eUnSet, eSubject, eSubject, eSubject}; -const int SenderInvertSortString[eUnSet] = { eSender, eSender, eSender, eSender, eRSender, eUnSet, eSender}; - - - /*----------------------------------------------------------------------------*/ -/* - * Translates sortoption String to its SortEnum representation - * returns the enum matching the string; defaults to RDate - */ -//SortByEnum -int StrToESort (const StrBuf *sortby) -{////todoo: hash - int result = eDate; - - if (!IsEmptyStr(ChrPtr(sortby))) while (result < eUnSet){ - if (!strcasecmp(ChrPtr(sortby), - SortByStrings[result])) - return result; - result ++; - } - return eRDate; -} - - -typedef int (*QSortFunction) (const void*, const void*); - -/* - * qsort() compatible function to compare two longs in descending order. - */ -int longcmp_r(const void *s1, const void *s2) { - long l1; - long l2; - - l1 = *(long *)GetSearchPayload(s1); - l2 = *(long *)GetSearchPayload(s2); - - if (l1 > l2) return(-1); - if (l1 < l2) return(+1); - return(0); -} - -/* - * qsort() compatible function to compare two longs in descending order. - */ -int qlongcmp_r(const void *s1, const void *s2) { - long l1 = (long) s1; - long l2 = (long) s2; - - if (l1 > l2) return(-1); - if (l1 < l2) return(+1); - return(0); -} - - -/* - * qsort() compatible function to compare two message summary structs by ascending subject. - */ -int summcmp_subj(const void *s1, const void *s2) { - message_summary *summ1; - message_summary *summ2; - - summ1 = (message_summary *)GetSearchPayload(s1); - summ2 = (message_summary *)GetSearchPayload(s2); - return strcasecmp(ChrPtr(summ1->subj), ChrPtr(summ2->subj)); -} - -/* - * qsort() compatible function to compare two message summary structs by descending subject. - */ -int summcmp_rsubj(const void *s1, const void *s2) { - message_summary *summ1; - message_summary *summ2; - - summ1 = (message_summary *)GetSearchPayload(s1); - summ2 = (message_summary *)GetSearchPayload(s2); - return strcasecmp(ChrPtr(summ2->subj), ChrPtr(summ1->subj)); -} - -/* - * qsort() compatible function to compare two message summary structs by ascending sender. - */ -int summcmp_sender(const void *s1, const void *s2) { - message_summary *summ1; - message_summary *summ2; - - summ1 = (message_summary *)GetSearchPayload(s1); - summ2 = (message_summary *)GetSearchPayload(s2); - return strcasecmp(ChrPtr(summ1->from), ChrPtr(summ2->from)); -} - -/* - * qsort() compatible function to compare two message summary structs by descending sender. - */ -int summcmp_rsender(const void *s1, const void *s2) { - message_summary *summ1; - message_summary *summ2; - - summ1 = (message_summary *)GetSearchPayload(s1); - summ2 = (message_summary *)GetSearchPayload(s2); - return strcasecmp(ChrPtr(summ2->from), ChrPtr(summ1->from)); -} - -/* - * qsort() compatible function to compare two message summary structs by ascending date. - */ -int summcmp_date(const void *s1, const void *s2) { - message_summary *summ1; - message_summary *summ2; - - summ1 = (message_summary *)GetSearchPayload(s1); - summ2 = (message_summary *)GetSearchPayload(s2); - - if (summ1->date < summ2->date) return -1; - else if (summ1->date > summ2->date) return +1; - else return 0; -} - -/* - * qsort() compatible function to compare two message summary structs by descending date. - */ -int summcmp_rdate(const void *s1, const void *s2) { - message_summary *summ1; - message_summary *summ2; - - summ1 = (message_summary *)GetSearchPayload(s1); - summ2 = (message_summary *)GetSearchPayload(s2); - - if (summ1->date < summ2->date) return +1; - else if (summ1->date > summ2->date) return -1; - else return 0; -} - - - - /* @@ -275,19 +93,14 @@ int read_message(StrBuf *Target, const char *tmpl, long tmpllen, long msgnum, in Done = 1; if (state < 2) { lprintf(1, _("unexpected end of message")); - StrBufAppendPrintf(Target, ""); - StrBufAppendPrintf(Target, _("unexpected end of message")); - StrBufAppendPrintf(Target, " (1)

\n"); - StrBufAppendPrintf(Target, "\n"); - FreeStrBuf(&Buf); - FreeStrBuf(&HdrToken); - DestroyMessageSummary(Msg); - FreeStrBuf(&FoundCharset); - return 0; - } - else { - break; + + Msg->MsgBody->ContentType = NewStrBufPlain(HKEY("text/html")); + StrBufAppendPrintf(Msg->MsgBody->Data, "
"); + StrBufAppendPrintf(Msg->MsgBody->Data, _("unexpected end of message")); + StrBufAppendPrintf(Msg->MsgBody->Data, " (1)

\n"); + StrBufAppendPrintf(Msg->MsgBody->Data, "
\n"); } + break; } switch (state) { case 0:/* Citadel Message Headers */ @@ -1123,8 +936,14 @@ int load_msg_ptrs(char *servcmd, int with_headers) } - - +inline message_summary* GetMessagePtrAt(int n, HashList *Summ) +{ + void *vMsg; + if (Summ == NULL) + return NULL; + GetHash(Summ, (const char*)&n, sizeof(n), &vMsg); + return (message_summary*) vMsg; +} /* @@ -1134,6 +953,7 @@ int load_msg_ptrs(char *servcmd, int with_headers) */ void readloop(char *oper) { + StrBuf *BBViewToolBar = NULL; void *vMsg; message_summary *Msg; char cmd[256] = ""; @@ -1141,6 +961,7 @@ void readloop(char *oper) char old_msgs[SIZ]; int a = 0; int b = 0; + int n; int nummsgs; long startmsg; int maxmsgs; @@ -1159,94 +980,117 @@ void readloop(char *oper) int highest_displayed = 0; addrbookent *addrbook = NULL; int num_ab = 0; - const StrBuf *sortby = NULL; - //SortByEnum - int SortBy = eRDate; - const StrBuf *sortpref_value; int bbs_reverse = 0; struct wcsession *WCC = WC; /* This is done to make it run faster; WC is a function */ HashPos *at; const char *HashKey; long HKLen; + int care_for_empty_list = 0; + int load_seen = 0; + int sortit = 0; - if (WCC->wc_view == VIEW_WIKI) { + switch (WCC->wc_view) { + case VIEW_WIKI: sprintf(buf, "wiki?room=%s&page=home", WCC->wc_roomname); http_redirect(buf); return; - } - - startmsg = lbstr("startmsg"); - maxmsgs = ibstr("maxmsgs"); - is_summary = (ibstr("is_summary") && !WCC->is_mobile); - if (maxmsgs == 0) maxmsgs = DEFAULT_MAXMSGS; - - sortpref_value = get_room_pref("sort"); - - sortby = sbstr("sortby"); - if ( (!IsEmptyStr(ChrPtr(sortby))) && - (strcasecmp(ChrPtr(sortby), ChrPtr(sortpref_value)) != 0)) { - set_room_pref("sort", NewStrBufDup(sortby), 1); - sortpref_value = NULL; - sortpref_value = sortby; - } - - SortBy = StrToESort(sortpref_value); - /* message board sort */ - if (SortBy == eReverse) { - bbs_reverse = 1; - } - else { - bbs_reverse = 0; - } - - output_headers(1, 1, 1, 0, 0, 0); - - /* - * When in summary mode, always show ALL messages instead of just - * new or old. Otherwise, show what the user asked for. - */ - if (!strcmp(oper, "readnew")) { - strcpy(cmd, "MSGS NEW"); - } - else if (!strcmp(oper, "readold")) { - strcpy(cmd, "MSGS OLD"); - } - else if (!strcmp(oper, "do_search")) { - snprintf(cmd, sizeof(cmd), "MSGS SEARCH|%s", bstr("query")); - } - else { + case VIEW_CALENDAR: + load_seen = 1; + is_calendar = 1; + strcpy(cmd, "MSGS ALL|||1"); + maxmsgs = 32767; + parse_calendar_view_request(&calv); + case VIEW_TASKS: + is_tasks = 1; strcpy(cmd, "MSGS ALL"); - } + maxmsgs = 32767; + case VIEW_NOTES: + is_notes = 1; + strcpy(cmd, "MSGS ALL"); + maxmsgs = 32767; + wprintf("
\n"); + case VIEW_ADDRESSBOOK: + is_singlecard = ibstr("is_singlecard"); + if (maxmsgs > 1) { + is_addressbook = 1; + if (!strcmp(oper, "do_search")) { + snprintf(cmd, sizeof(cmd), "MSGS SEARCH|%s", bstr("query")); + } + else { + strcpy(cmd, "MSGS ALL"); + } + maxmsgs = 9999999; + break; + } - if ((WCC->wc_view == VIEW_MAILBOX) && (maxmsgs > 1) && !WCC->is_mobile) { - is_summary = 1; - if (!strcmp(oper, "do_search")) { - snprintf(cmd, sizeof(cmd), "MSGS SEARCH|%s", bstr("query")); + default: + care_for_empty_list = 1; + startmsg = lbstr("startmsg"); + maxmsgs = ibstr("maxmsgs"); + is_summary = (ibstr("is_summary") && !WCC->is_mobile); + if (maxmsgs == 0) maxmsgs = DEFAULT_MAXMSGS; + + + + /* + * When in summary mode, always show ALL messages instead of just + * new or old. Otherwise, show what the user asked for. + */ + if (!strcmp(oper, "readnew")) { + strcpy(cmd, "MSGS NEW"); } - else { - strcpy(cmd, "MSGS ALL"); + else if (!strcmp(oper, "readold")) { + strcpy(cmd, "MSGS OLD"); } - } - - if ((WCC->wc_view == VIEW_ADDRESSBOOK) && (maxmsgs > 1)) { - is_addressbook = 1; - if (!strcmp(oper, "do_search")) { + else if (!strcmp(oper, "do_search")) { snprintf(cmd, sizeof(cmd), "MSGS SEARCH|%s", bstr("query")); } else { strcpy(cmd, "MSGS ALL"); } - maxmsgs = 9999999; + + if ((WCC->wc_view == VIEW_MAILBOX) && (maxmsgs > 1) && !WCC->is_mobile) { + is_summary = 1; + if (!strcmp(oper, "do_search")) { + snprintf(cmd, sizeof(cmd), "MSGS SEARCH|%s", bstr("query")); + } + else { + strcpy(cmd, "MSGS ALL"); + } + } + + is_bbview = !is_summary; + if (is_summary) { /**< fetch header summary */ + load_seen = 1; + snprintf(cmd, sizeof(cmd), "MSGS %s|%s||1", + (!strcmp(oper, "do_search") ? "SEARCH" : "ALL"), + (!strcmp(oper, "do_search") ? bstr("query") : "") + ); + startmsg = 1; + maxmsgs = 9999999; + } + if (startmsg == 0L) { + if (bbs_reverse) { + Msg = GetMessagePtrAt((nummsgs >= maxmsgs) ? (nummsgs - maxmsgs) : 0, WCC->summ); + startmsg = (Msg==NULL)? 0 : Msg->msgnum; + } + else { + Msg = GetMessagePtrAt(0, WCC->summ); + startmsg = (Msg==NULL)? 0 : Msg->msgnum; + } + } + sortit = is_summary || WCC->is_mobile; } - if (is_summary) { /**< fetch header summary */ - snprintf(cmd, sizeof(cmd), "MSGS %s|%s||1", - (!strcmp(oper, "do_search") ? "SEARCH" : "ALL"), - (!strcmp(oper, "do_search") ? bstr("query") : "") - ); - startmsg = 1; - maxmsgs = 9999999; - } + + + + + + + output_headers(1, 1, 1, 0, 0, 0); + + /* if (WCC->is_mobile) { maxmsgs = 20; snprintf(cmd, sizeof(cmd), "MSGS %s|%s||1", @@ -1261,42 +1105,11 @@ void readloop(char *oper) * and new messages, so we can do that pretty boldface thing for the * new messages. */ - strcpy(old_msgs, ""); - if ((is_summary) || (WCC->wc_default_view == VIEW_CALENDAR) || WCC->is_mobile){ - serv_puts("GTSN"); - serv_getln(buf, sizeof buf); - if (buf[0] == '2') { - strcpy(old_msgs, &buf[4]); - } - } - is_singlecard = ibstr("is_singlecard"); - - if (WCC->wc_default_view == VIEW_CALENDAR) { /**< calendar */ - is_calendar = 1; - strcpy(cmd, "MSGS ALL|||1"); - maxmsgs = 32767; - parse_calendar_view_request(&calv); - } - if (WCC->wc_default_view == VIEW_TASKS) { /**< tasks */ - is_tasks = 1; - strcpy(cmd, "MSGS ALL"); - maxmsgs = 32767; - } - if (WCC->wc_default_view == VIEW_NOTES) { /**< notes */ - is_notes = 1; - strcpy(cmd, "MSGS ALL"); - maxmsgs = 32767; - } - - if (is_notes) { - wprintf("
\n"); - } nummsgs = load_msg_ptrs(cmd, (is_summary || WCC->is_mobile)); if (nummsgs == 0) { - - if ((!is_tasks) && (!is_calendar) && (!is_notes) && (!is_addressbook)) { + if (care_for_empty_list) { wprintf("

"); if (!strcmp(oper, "readnew")) { wprintf(_("No new messages.")); @@ -1311,10 +1124,15 @@ void readloop(char *oper) goto DONE; } - if ((is_summary) || (WCC->wc_default_view == VIEW_CALENDAR) || WCC->is_mobile){ + if (load_seen){ void *vMsg; - message_summary *Msg; + strcpy(old_msgs, ""); + serv_puts("GTSN"); + serv_getln(buf, sizeof buf); + if (buf[0] == '2') { + strcpy(old_msgs, &buf[4]); + } at = GetNewHashPos(); while (GetNextHashPos(WCC->summ, at, &HKLen, &HashKey, &vMsg)) { /** Are you a new message, or an old message? */ @@ -1331,110 +1149,62 @@ void readloop(char *oper) DeleteHashPos(&at); } - if (startmsg == 0L) { - if (bbs_reverse) { - startmsg = WCC->msgarr[(nummsgs >= maxmsgs) ? (nummsgs - maxmsgs) : 0]; - } - else { - startmsg = WCC->msgarr[0]; - } - } - - if (is_summary || WCC->is_mobile) { - SortByPayload(WCC->summ, SortFuncs[SortBy]); + if (sortit) { + CompareFunc SortIt; + SortIt = RetrieveSort(CTX_MAILSUM, NULL, + HKEY("date"), 2); + if (SortIt != NULL) + SortByPayload(WCC->summ, SortIt); } if (is_summary) { - - wprintf("\n" - ); - - /** note that Date and Delete are now in the same column */ - wprintf("
" - "
" - "" - "" - ); - wprintf("\n" - "\n" - "" - "\n" - , - SUBJ_COL_WIDTH_PCT, - _("Subject"), - SortByStrings[SubjectInvertSortString[SortBy]], - SortIcons[SortSubjectToIcon[SortBy]], - SENDER_COL_WIDTH_PCT, - _("Sender"), - SortByStrings[SenderInvertSortString[SortBy]], - SortIcons[SortSenderToIcon[SortBy]], - DATE_PLUS_BUTTONS_WIDTH_PCT, - _("Date"), - SortByStrings[DateInvertSortString[SortBy]], - SortIcons[SortDateToIcon[SortBy]], - _("Delete") - ); - wprintf("
%s %s %s \n" - " " - "" - "
\n"); - wprintf("
" - - "
\n" - "" - ); + do_template("summary_header", NULL); } else if (WCC->is_mobile) { wprintf("
"); } - /** - * Set the "is_bbview" variable if it appears that we are looking at - * a classic bulletin board view. - */ - if ((!is_tasks) && (!is_calendar) && (!is_addressbook) - && (!is_notes) && (!is_singlecard) && (!is_summary)) { - is_bbview = 1; - } - /** * If we're not currently looking at ALL requested * messages, then display the selector bar */ if (is_bbview) { + const char *selected; + StrBuf *Selector = NewStrBuf(); + BBViewToolBar = NewStrBuf(); +///// DoTemplate("bbview_scrollbar"); /** begin bbview scroller */ - wprintf("
\n

"); - wprintf(_("Reading #"));//// TODO this isn't used, should it? : , lowest_displayed, highest_displayed); + StrBufAppendPrintf(BBViewToolBar, " \n

"); + StrBufAppendPrintf(BBViewToolBar, _("Reading #"));//// TODO this isn't used, should it? : , lowest_displayed, highest_displayed); - wprintf("\n"); if (bbs_reverse) { for (b=nummsgs-1; b>=0; b = b - maxmsgs) { hi = b + 1; lo = b - maxmsgs + 2; if (lo < 1) lo = 1; - wprintf(" \n", - ((WCC->msgarr[lo-1] == startmsg) ? "selected" : ""), - oper, - WCC->msgarr[lo-1], - maxmsgs, - is_summary, - hi, lo); + + Msg = GetMessagePtrAt(lo-1, WCC->summ); + n = (Msg==NULL)? 0 : Msg->msgnum; + selected = ((n == startmsg) ? "selected" : ""); + + StrBufAppendPrintf(Selector, + " \n", + selected, + oper, + + + maxmsgs, + is_summary, + hi, lo); } } else { @@ -1442,50 +1212,62 @@ void readloop(char *oper) lo = b + 1; hi = b + maxmsgs + 1; if (hi > nummsgs) hi = nummsgs; - wprintf(" \n", - ((WCC->msgarr[b] == startmsg) ? "selected" : ""), - oper, - WCC->msgarr[lo-1], - maxmsgs, - is_summary, - lo, hi); + + Msg = GetMessagePtrAt(b, WCC->summ); + n = (Msg==NULL)? 0 : Msg->msgnum; + selected = ((n == startmsg) ? "selected" : ""); + Msg = GetMessagePtrAt(lo-1, WCC->summ); + StrBufAppendPrintf(Selector, + " \n", + selected, + oper, + (Msg==NULL)? 0 : Msg->msgnum, + maxmsgs, + is_summary, + lo, hi); } } - wprintf(""); - wprintf(" "); - wprintf(_("of %d messages."), nummsgs); + (Msg==NULL)? 0 : Msg->msgnum); + StrBufAppendPrintf(BBViewToolBar, _("All")); + + StrBufAppendPrintf(BBViewToolBar, ""); + StrBufAppendPrintf(BBViewToolBar, " "); + StrBufAppendPrintf(BBViewToolBar, _("of %d messages."), nummsgs); /** forward/reverse */ - wprintf(""); - wprintf(_("oldest to newest")); - wprintf("    "); + StrBufAppendPrintf(BBViewToolBar, ">"); + StrBufAppendPrintf(BBViewToolBar, _("oldest to newest")); + StrBufAppendPrintf(BBViewToolBar, "    "); - wprintf(""); - wprintf(_("newest to oldest")); - wprintf("\n"); + StrBufAppendPrintf(BBViewToolBar, ">"); + StrBufAppendPrintf(BBViewToolBar, _("newest to oldest")); + StrBufAppendPrintf(BBViewToolBar, "\n"); - wprintf("

\n"); + StrBufAppendPrintf(BBViewToolBar, "

\n"); + StrBufAppendBuf(WCC->WBuf, BBViewToolBar, 0); /** end bbview scroller */ } @@ -1537,7 +1319,7 @@ void readloop(char *oper) /** Output loop */ if (displayed_msgs != NULL) { if (bbs_reverse) { - qsort(displayed_msgs, num_displayed, sizeof(long), qlongcmp_r); + ////TODOqsort(displayed_msgs, num_displayed, sizeof(long), qlongcmp_r); } /** if we do a split bbview in the future, begin messages div here */ @@ -1582,81 +1364,7 @@ void readloop(char *oper) */ if (is_bbview) { /** begin bbview scroller */ - wprintf("
\n

"); - wprintf(_("Reading #")); /// TODO: this isn't used: , lowest_displayed, highest_displayed); - - wprintf(" "); - wprintf(_("of %d messages."), nummsgs); - - /** forward/reverse */ - wprintf(""); - wprintf(_("oldest to newest")); - wprintf("    "); - wprintf(""); - wprintf(_("newest to oldest")); - wprintf("\n"); - - wprintf("

\n"); - /** end bbview scroller */ + StrBufAppendBuf(WCC->WBuf, BBViewToolBar, 0); } DONE: @@ -2248,5 +1956,6 @@ InitModule_MSG WebcitAddUrlHandler(HKEY("mobilemsg"), mobile_message_view, NEED_URL); WebcitAddUrlHandler(HKEY("msgheaders"), display_headers, NEED_URL); + return ; } diff --git a/webcit/msg_renderers.c b/webcit/msg_renderers.c index b64b892af..11a2613a0 100644 --- a/webcit/msg_renderers.c +++ b/webcit/msg_renderers.c @@ -68,6 +68,116 @@ void RegisterMimeRenderer(const char *HeaderName, long HdrNLen, RenderMimeFunc M /*----------------------------------------------------------------------------*/ +/* + * qsort() compatible function to compare two longs in descending order. + */ +int longcmp_r(const void *s1, const void *s2) { + long l1; + long l2; + + l1 = *(long *)GetSearchPayload(s1); + l2 = *(long *)GetSearchPayload(s2); + + if (l1 > l2) return(-1); + if (l1 < l2) return(+1); + return(0); +} + +/* + * qsort() compatible function to compare two longs in descending order. + */ +int qlongcmp_r(const void *s1, const void *s2) { + long l1 = (long) s1; + long l2 = (long) s2; + + if (l1 > l2) return(-1); + if (l1 < l2) return(+1); + return(0); +} + + +/* + * qsort() compatible function to compare two message summary structs by ascending subject. + */ +int summcmp_subj(const void *s1, const void *s2) { + message_summary *summ1; + message_summary *summ2; + + summ1 = (message_summary *)GetSearchPayload(s1); + summ2 = (message_summary *)GetSearchPayload(s2); + return strcasecmp(ChrPtr(summ1->subj), ChrPtr(summ2->subj)); +} + +/* + * qsort() compatible function to compare two message summary structs by descending subject. + */ +int summcmp_rsubj(const void *s1, const void *s2) { + message_summary *summ1; + message_summary *summ2; + + summ1 = (message_summary *)GetSearchPayload(s1); + summ2 = (message_summary *)GetSearchPayload(s2); + return strcasecmp(ChrPtr(summ2->subj), ChrPtr(summ1->subj)); +} + +/* + * qsort() compatible function to compare two message summary structs by ascending sender. + */ +int summcmp_sender(const void *s1, const void *s2) { + message_summary *summ1; + message_summary *summ2; + + summ1 = (message_summary *)GetSearchPayload(s1); + summ2 = (message_summary *)GetSearchPayload(s2); + return strcasecmp(ChrPtr(summ1->from), ChrPtr(summ2->from)); +} + +/* + * qsort() compatible function to compare two message summary structs by descending sender. + */ +int summcmp_rsender(const void *s1, const void *s2) { + message_summary *summ1; + message_summary *summ2; + + summ1 = (message_summary *)GetSearchPayload(s1); + summ2 = (message_summary *)GetSearchPayload(s2); + return strcasecmp(ChrPtr(summ2->from), ChrPtr(summ1->from)); +} + +/* + * qsort() compatible function to compare two message summary structs by ascending date. + */ +int summcmp_date(const void *s1, const void *s2) { + message_summary *summ1; + message_summary *summ2; + + summ1 = (message_summary *)GetSearchPayload(s1); + summ2 = (message_summary *)GetSearchPayload(s2); + + if (summ1->date < summ2->date) return -1; + else if (summ1->date > summ2->date) return +1; + else return 0; +} + +/* + * qsort() compatible function to compare two message summary structs by descending date. + */ +int summcmp_rdate(const void *s1, const void *s2) { + message_summary *summ1; + message_summary *summ2; + + summ1 = (message_summary *)GetSearchPayload(s1); + summ2 = (message_summary *)GetSearchPayload(s2); + + if (summ1->date < summ2->date) return +1; + else if (summ1->date > summ2->date) return -1; + else return 0; +} + +/*----------------------------------------------------------------------------*/ + + + void examine_nhdr(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset) { @@ -588,7 +698,7 @@ void render_MAIL_text_plain(wc_mime_attachment *Mime, StrBuf *RawData, StrBuf *F StrBuf *Line2; StrBuf *Target; - int ConvertIt = 0; + int ConvertIt = 1; int bn = 0; int bq = 0; int i, n, done = 0; @@ -617,7 +727,7 @@ void render_MAIL_text_plain(wc_mime_attachment *Mime, StrBuf *RawData, StrBuf *F cs = FoundCharset; else if (StrLength(WC->DefaultCharset) > 0) cs = WC->DefaultCharset; - if (cs == 0) { + if (cs == NULL) { ConvertIt = 0; } else { @@ -830,12 +940,26 @@ void tmplput_ATT_FileName(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, vo - - void InitModule_MSGRENDERERS (void) { + RegisterSortFunc(HKEY("date"), + NULL, 0, + summcmp_date, + summcmp_rdate, + CTX_MAILSUM); + RegisterSortFunc(HKEY("subject"), + NULL, 0, + summcmp_subj, + summcmp_rsubj, + CTX_MAILSUM); + RegisterSortFunc(HKEY("sender"), + NULL, 0, + summcmp_sender, + summcmp_rsender, + CTX_MAILSUM); + RegisterNamespace("MAIL:SUMM:DATESTR", 0, 0, tmplput_MAIL_SUMM_DATE_STR, CTX_MAILSUM); RegisterNamespace("MAIL:SUMM:DATENO", 0, 0, tmplput_MAIL_SUMM_DATE_NO, CTX_MAILSUM); RegisterNamespace("MAIL:SUMM:N", 0, 0, tmplput_MAIL_SUMM_N, CTX_MAILSUM); diff --git a/webcit/rss.c b/webcit/rss.c index d17fe3896..ffdf08c4f 100644 --- a/webcit/rss.c +++ b/webcit/rss.c @@ -45,6 +45,8 @@ void display_rss_control(char *reply_to, char *subject) */ void display_rss(char *roomname, StrBuf *request_method) { + message_summary *Msg; + struct wcsession *WCC = WC; int nummsgs; int a, b; int bq = 0; @@ -71,14 +73,14 @@ void display_rss(char *roomname, StrBuf *request_method) char content_type[256]; char charset[256]; - if (!WC->logged_in) { + if (!WCC->logged_in) { #ifdef ALLOW_ANON_RSS serv_printf("USER %s", ANON_RSS_USER); serv_getln(buf, sizeof buf); serv_printf("PASS %s", ANON_RSS_PASS); serv_getln(buf, sizeof buf); become_logged_in(ANON_RSS_USER, ANON_RSS_PASS, buf); - WC->killthis = 1; + WCC->killthis = 1; #else authorization_required(_("Not logged in")); return; @@ -106,7 +108,9 @@ void display_rss(char *roomname, StrBuf *request_method) /** Read time of last message immediately */ - serv_printf("MSG4 %ld", WC->msgarr[nummsgs - 1]); + Msg = GetMessagePtrAt(nummsgs - 1, WCC->summ); + + serv_printf("MSG4 %ld", (Msg==NULL)? 0 : Msg->msgnum); serv_getln(buf, sizeof buf); if (buf[0] == '1') { while (serv_getln(buf, sizeof buf), strcasecmp(buf, "000")) { @@ -148,10 +152,10 @@ void display_rss(char *roomname, StrBuf *request_method) /* "); svput("XML_STYLE", WCS_STRING, ""); - svput("ROOM", WCS_STRING, WC->wc_roomname); + svput("ROOM", WCS_STRING, WCC->wc_roomname); svput("NODE", WCS_STRING, serv_info.serv_humannode); // Fix me - svprintf(HKEY("ROOM_LINK"), WCS_STRING, "%s://%s/", (is_https ? "https" : "http"), WC->http_host); + svprintf(HKEY("ROOM_LINK"), WCS_STRING, "%s://%s/", (is_https ? "https" : "http"), WCC->http_host); /** Get room info for description */ serv_puts("RINF"); @@ -175,7 +179,8 @@ void display_rss(char *roomname, StrBuf *request_method) /** Read all messages and output as RSS items */ for (a = 0; a < nummsgs; ++a) { /** Read message and output each as RSS item */ - serv_printf("MSG4 %ld", WC->msgarr[a]); + Msg = GetMessagePtrAt(a, WCC->summ); + serv_printf("MSG4 %ld", (Msg==NULL)? 0 : Msg->msgnum); serv_getln(buf, sizeof buf); if (buf[0] != '1') continue; @@ -334,7 +339,9 @@ void display_rss(char *roomname, StrBuf *request_method) } /** HTML is fun, but we've got to strip it first */ else if (!strcasecmp(content_type, "text/html")) { - output_html(charset, 0, WC->msgarr[a], NULL, NULL); + Msg = GetMessagePtrAt(a, WCC->summ); + + output_html(charset, 0, (Msg==NULL)? 0 : Msg->msgnum, NULL, NULL); } ENDBODY: diff --git a/webcit/smtpqueue.c b/webcit/smtpqueue.c index 16a2491ff..a830b660f 100644 --- a/webcit/smtpqueue.c +++ b/webcit/smtpqueue.c @@ -164,6 +164,8 @@ void display_queue_msg(long msgnum) void display_smtpqueue_inner_div(void) { + message_summary *Msg; + struct wcsession *WCC = WC; int i; int num_msgs; @@ -171,7 +173,7 @@ void display_smtpqueue_inner_div(void) { * If not, we don't have access to the queue. */ gotoroom("__CitadelSMTPspoolout__"); - if (!strcasecmp(WC->wc_roomname, "__CitadelSMTPspoolout__")) { + if (!strcasecmp(WCC->wc_roomname, "__CitadelSMTPspoolout__")) { num_msgs = load_msg_ptrs("MSGS ALL", 0); if (num_msgs > 0) { @@ -192,7 +194,9 @@ void display_smtpqueue_inner_div(void) { wprintf("\n"); for (i=0; imsgarr[i]); + Msg = GetMessagePtrAt(i, WCC->summ); + + display_queue_msg((Msg==NULL)? 0 : Msg->msgnum); } wprintf("
"); diff --git a/webcit/subst.c b/webcit/subst.c index db8a6ccb3..ce0cd8d1b 100644 --- a/webcit/subst.c +++ b/webcit/subst.c @@ -30,6 +30,7 @@ HashList *LocalTemplateCache; HashList *GlobalNS; HashList *Iterators; HashList *Conditionals; +HashList *SortHash; int LoadTemplates = 0; @@ -56,6 +57,7 @@ typedef struct _HashHandler { }HashHandler; void *load_template(StrBuf *filename, StrBuf *Key, HashList *PutThere); +int EvaluateConditional(StrBuf *Target, WCTemplateToken *Tokens, WCTemplate *pTmpl, void *Context, int Neg, int state, int ContextType); void RegisterNS(const char *NSName, long len, @@ -463,49 +465,6 @@ void pvo_do_cmd(StrBuf *Target, StrBuf *servcmd) { } } - -/** - * \brief puts string into the template and computes which escape methon we should use - * \param Source the string we should put into the template - * \param FormatTypeIndex where should we look for escape types if? - */ -void StrBufAppendTemplate(StrBuf *Target, - int nArgs, - WCTemplateToken *Tokens, - void *Context, int ContextType, - const StrBuf *Source, int FormatTypeIndex) -{ - struct wcsession *WCC; - StrBuf *Buf; - char EscapeAs = ' '; - - if ((FormatTypeIndex < Tokens->nParameters) && - (Tokens->Params[FormatTypeIndex]->Type == TYPE_STR) && - (Tokens->Params[FormatTypeIndex]->len == 1)) { - EscapeAs = *Tokens->Params[FormatTypeIndex]->Start; - } - - switch(EscapeAs) - { - case 'H': - WCC = WC; - Buf = NewStrBufPlain(NULL, StrLength(Source)); - StrBuf_RFC822_to_Utf8(Buf, - Source, - (WCC!=NULL)? WCC->DefaultCharset : NULL, - NULL); - StrEscAppend(Target, Buf, NULL, 0, 0); - FreeStrBuf(&Buf); - break; - case 'X': - StrEscAppend(Target, Source, NULL, 0, 0); - break; - default: - StrBufAppendBuf(Target, Source, 0); - } -} - - void GetTemplateTokenString(WCTemplateToken *Tokens, int N, const char **Value, @@ -676,6 +635,49 @@ int CompareSubstToStrBuf(StrBuf *Compare, TemplateParam *ParamToLookup) } + +/** + * \brief puts string into the template and computes which escape methon we should use + * \param Source the string we should put into the template + * \param FormatTypeIndex where should we look for escape types if? + */ +void StrBufAppendTemplate(StrBuf *Target, + int nArgs, + WCTemplateToken *Tokens, + void *Context, int ContextType, + const StrBuf *Source, int FormatTypeIndex) +{ + struct wcsession *WCC; + StrBuf *Buf; + char EscapeAs = ' '; + + if ((FormatTypeIndex < Tokens->nParameters) && + (Tokens->Params[FormatTypeIndex]->Type == TYPE_STR) && + (Tokens->Params[FormatTypeIndex]->len == 1)) { + EscapeAs = *Tokens->Params[FormatTypeIndex]->Start; + } + + switch(EscapeAs) + { + case 'H': + WCC = WC; + Buf = NewStrBufPlain(NULL, StrLength(Source)); + StrBuf_RFC822_to_Utf8(Buf, + Source, + (WCC!=NULL)? WCC->DefaultCharset : NULL, + NULL); + StrEscAppend(Target, Buf, NULL, 0, 0); + FreeStrBuf(&Buf); + break; + case 'X': + StrEscAppend(Target, Source, NULL, 0, 0); + break; + default: + StrBufAppendBuf(Target, Source, 0); + } +} + + void PutNewToken(WCTemplate *Template, WCTemplateToken *NewToken) { if (Template->nTokensUsed + 1 >= Template->TokenSpace) { @@ -987,104 +989,253 @@ WCTemplateToken *NewTemplateSubstitute(StrBuf *Buf, -int EvaluateConditional(StrBuf *Target, WCTemplateToken *Tokens, WCTemplate *pTmpl, void *Context, int Neg, int state, int ContextType) -{ - ConditionalStruct *Cond; - if ((Tokens->Params[0]->len == 1) && - (Tokens->Params[0]->Start[0] == 'X')) - return (state != 0)?Tokens->Params[1]->lvalue:0; - - Cond = (ConditionalStruct *) Tokens->PreEval; - if (Cond == NULL) { - lprintf(1, "Conditional [%s] (in '%s' line %ld); unknown![%s]\n", - Tokens->Params[0]->Start, - ChrPtr(pTmpl->FileName), - Tokens->Line, - ChrPtr(Tokens->FlatToken)); - return 1; - } - if (Tokens->nParameters < Cond->nParams) { - lprintf(1, "Conditional [%s] (in '%s' line %ld); needs %ld Params![%s]\n", - Tokens->Params[0]->Start, - ChrPtr(pTmpl->FileName), - Tokens->Line, - Cond->nParams, - ChrPtr(Tokens->FlatToken)); - StrBufAppendPrintf( - Target, - "
\nConditional [%s] (in '%s' line %ld); needs %ld Params!\n[%s]\n
\n", - Tokens->Params[0]->Start, - ChrPtr(pTmpl->FileName), - Tokens->Line, - Cond->nParams, - ChrPtr(Tokens->FlatToken)); - return 0; - } - if (Cond->CondF(Tokens, Context, ContextType) == Neg) - return Tokens->Params[1]->lvalue; - return 0; +/** + * \brief Display a variable-substituted template + * \param templatename template file to load + */ +void *prepare_template(StrBuf *filename, StrBuf *Key, HashList *PutThere) +{ + WCTemplate *NewTemplate; + NewTemplate = (WCTemplate *) malloc(sizeof(WCTemplate)); + NewTemplate->Data = NULL; + NewTemplate->FileName = NewStrBufDup(filename); + NewTemplate->nTokensUsed = 0; + NewTemplate->TokenSpace = 0; + NewTemplate->Tokens = NULL; + + Put(PutThere, ChrPtr(Key), StrLength(Key), NewTemplate, FreeWCTemplate); + return NewTemplate; } /** - * \brief executes one token - * \param Target buffer to append to - * \param Token da to process. - * \param Template we're iterating - * \param Context Contextpoointer to pass in - * \param state are we in conditional state? - * \param ContextType what type of information does context giv us? + * \brief Display a variable-substituted template + * \param templatename template file to load */ -int EvaluateToken(StrBuf *Target, WCTemplateToken *Tokens, WCTemplate *pTmpl, void *Context, int state, int ContextType) +void *load_template(StrBuf *filename, StrBuf *Key, HashList *PutThere) { - HashHandler *Handler; - void *vVar; -// much output, since pName is not terminated... -// lprintf(1,"Doing token: %s\n",Token->pName); + int fd; + struct stat statbuf; + const char *pS, *pE, *pch, *Err; + long Line; + int pos; + WCTemplate *NewTemplate; - switch (Tokens->Flags) { - case SV_GETTEXT: - TmplGettext(Target, Tokens->nParameters, Tokens); - break; - case SV_CONDITIONAL: /** Forward conditional evaluation */ - return EvaluateConditional(Target, Tokens, pTmpl, Context, 1, state, ContextType); - break; - case SV_NEG_CONDITIONAL: /** Reverse conditional evaluation */ - return EvaluateConditional(Target, Tokens, pTmpl, Context, 0, state, ContextType); - break; - case SV_CUST_STR_CONDITIONAL: /** Conditional put custom strings from params */ - if (Tokens->nParameters >= 6) { - if (EvaluateConditional(Target, Tokens, pTmpl, Context, 0, state, ContextType)) - StrBufAppendBufPlain(Target, - Tokens->Params[5]->Start, - Tokens->Params[5]->len, - 0); - else - StrBufAppendBufPlain(Target, - Tokens->Params[4]->Start, - Tokens->Params[4]->len, - 0); + fd = open(ChrPtr(filename), O_RDONLY); + if (fd <= 0) { + lprintf(1, "ERROR: could not open template '%s' - %s\n", + ChrPtr(filename), strerror(errno)); + return NULL; + } + + if (fstat(fd, &statbuf) == -1) { + lprintf(1, "ERROR: could not stat template '%s' - %s\n", + ChrPtr(filename), strerror(errno)); + return NULL; + } + + NewTemplate = (WCTemplate *) malloc(sizeof(WCTemplate)); + NewTemplate->Data = NewStrBufPlain(NULL, statbuf.st_size); + NewTemplate->FileName = NewStrBufDup(filename); + NewTemplate->nTokensUsed = 0; + NewTemplate->TokenSpace = 0; + NewTemplate->Tokens = NULL; + if (StrBufReadBLOB(NewTemplate->Data, &fd, 1, statbuf.st_size, &Err) < 0) { + close(fd); + FreeWCTemplate(NewTemplate); + lprintf(1, "ERROR: reading template '%s' - %s
\n", + ChrPtr(filename), strerror(errno)); + return NULL; + } + close(fd); + + Line = 0; + pS = pch = ChrPtr(NewTemplate->Data); + pE = pS + StrLength(NewTemplate->Data); + while (pch < pE) { + const char *pts, *pte; + int InQuotes = 0; + int InDoubleQuotes = 0; + + /** Find one */ + pos = (-1); + for (; pch < pE; pch ++) { + if ((*pch=='<')&&(*(pch + 1)=='?')) + break; + if (*pch=='\n') Line ++; } - else { - lprintf(1, "Conditional [%s] (in '%s' line %ld); needs at least 6 Params![%s]\n", - Tokens->Params[0]->Start, - ChrPtr(pTmpl->FileName), - Tokens->Line, - ChrPtr(Tokens->FlatToken)); - StrBufAppendPrintf( - Target, - "
\nConditional [%s] (in '%s' line %ld); needs 6 Params!\n[%s]\n
\n", - Tokens->Params[0]->Start, - ChrPtr(pTmpl->FileName), - Tokens->Line, - ChrPtr(Tokens->FlatToken)); + if (pch >= pE) + continue; + pts = pch; + + /** Found one? parse it. */ + for (; pch < pE - 1; pch ++) { + if (*pch == '"') + InDoubleQuotes = ! InDoubleQuotes; + else if (*pch == '\'') + InQuotes = ! InQuotes; + else if ((!InQuotes && !InDoubleQuotes) && + ((*pch!='\\')&&(*(pch + 1)=='>'))) { + pch ++; + break; + } } - break; - case SV_SUBTEMPL: - if (Tokens->nParameters == 1) - DoTemplate(Tokens->Params[0]->Start, Tokens->Params[0]->len, NULL, NULL, ContextType); - break; + if (pch + 1 >= pE) + continue; + pte = pch; + PutNewToken(NewTemplate, + NewTemplateSubstitute(NewTemplate->Data, pS, pts, pte, Line, NewTemplate)); + pch ++; + } + if (LoadTemplates == 0) + Put(PutThere, ChrPtr(Key), StrLength(Key), NewTemplate, FreeWCTemplate); + return NewTemplate; +} + + +///void PrintTemplate(const char *Key, void *vSubst, int odd) +const char* PrintTemplate(void *vSubst) +{ + WCTemplate *Tmpl = vSubst; + + return ChrPtr(Tmpl->FileName); + +} + +int LoadTemplateDir(const char *DirName, HashList *wireless, HashList *big) +{ + StrBuf *FileName; + StrBuf *Tag; + StrBuf *Dir; + DIR *filedir = NULL; + struct dirent *filedir_entry; + int d_namelen; + int d_without_ext; + int IsMobile; + + Dir = NewStrBuf(); + StrBufPrintf(Dir, "%s/t", DirName); + filedir = opendir (ChrPtr(Dir)); + if (filedir == NULL) { + FreeStrBuf(&Dir); + return 0; + } + + FileName = NewStrBuf(); + Tag = NewStrBuf(); + while ((filedir_entry = readdir(filedir))) + { + char *MinorPtr; + char *PStart; +#ifdef _DIRENT_HAVE_D_NAMELEN + d_namelen = filedir_entry->d_namelen; +#else + d_namelen = strlen(filedir_entry->d_name); +#endif + d_without_ext = d_namelen; + while ((d_without_ext > 0) && (filedir_entry->d_name[d_without_ext] != '.')) + d_without_ext --; + if ((d_without_ext == 0) || (d_namelen < 3)) + continue; + if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~') + continue; /* Ignore backup files... */ + + IsMobile = (strstr(filedir_entry->d_name, ".m.html")!= NULL); + PStart = filedir_entry->d_name; + StrBufPrintf(FileName, "%s/%s", ChrPtr(Dir), filedir_entry->d_name); + MinorPtr = strchr(filedir_entry->d_name, '.'); + if (MinorPtr != NULL) + *MinorPtr = '\0'; + StrBufPlain(Tag, filedir_entry->d_name, MinorPtr - filedir_entry->d_name); + + if (LoadTemplates > 1) + lprintf(1, "%s %d %s\n",ChrPtr(FileName), IsMobile, ChrPtr(Tag)); + if (LoadTemplates == 0) + load_template(FileName, Tag, (IsMobile)?wireless:big); + else + prepare_template(FileName, Tag, (IsMobile)?wireless:big); + } + closedir(filedir); + FreeStrBuf(&FileName); + FreeStrBuf(&Tag); + FreeStrBuf(&Dir); + return 1; +} + +void InitTemplateCache(void) +{ + LoadTemplateDir(static_dirs[0], + WirelessTemplateCache, + TemplateCache); + LoadTemplateDir(static_dirs[1], + WirelessLocalTemplateCache, + LocalTemplateCache); +} + + + +/*----------------------------------------------------------------------------- + * Filling & processing Templates + */ +/** + * \brief executes one token + * \param Target buffer to append to + * \param Token da to process. + * \param Template we're iterating + * \param Context Contextpoointer to pass in + * \param state are we in conditional state? + * \param ContextType what type of information does context giv us? + */ +int EvaluateToken(StrBuf *Target, WCTemplateToken *Tokens, WCTemplate *pTmpl, void *Context, int state, int ContextType) +{ + HashHandler *Handler; + void *vVar; +// much output, since pName is not terminated... +// lprintf(1,"Doing token: %s\n",Token->pName); + + switch (Tokens->Flags) { + case SV_GETTEXT: + TmplGettext(Target, Tokens->nParameters, Tokens); + break; + case SV_CONDITIONAL: /** Forward conditional evaluation */ + return EvaluateConditional(Target, Tokens, pTmpl, Context, 1, state, ContextType); + break; + case SV_NEG_CONDITIONAL: /** Reverse conditional evaluation */ + return EvaluateConditional(Target, Tokens, pTmpl, Context, 0, state, ContextType); + break; + case SV_CUST_STR_CONDITIONAL: /** Conditional put custom strings from params */ + if (Tokens->nParameters >= 6) { + if (EvaluateConditional(Target, Tokens, pTmpl, Context, 0, state, ContextType)) + StrBufAppendBufPlain(Target, + Tokens->Params[5]->Start, + Tokens->Params[5]->len, + 0); + else + StrBufAppendBufPlain(Target, + Tokens->Params[4]->Start, + Tokens->Params[4]->len, + 0); + } + else { + lprintf(1, "Conditional [%s] (in '%s' line %ld); needs at least 6 Params![%s]\n", + Tokens->Params[0]->Start, + ChrPtr(pTmpl->FileName), + Tokens->Line, + ChrPtr(Tokens->FlatToken)); + StrBufAppendPrintf( + Target, + "
\nConditional [%s] (in '%s' line %ld); needs 6 Params!\n[%s]\n
\n", + Tokens->Params[0]->Start, + ChrPtr(pTmpl->FileName), + Tokens->Line, + ChrPtr(Tokens->FlatToken)); + } + break; + case SV_SUBTEMPL: + if (Tokens->nParameters == 1) + DoTemplate(Tokens->Params[0]->Start, Tokens->Params[0]->len, NULL, NULL, ContextType); + break; case SV_PREEVALUATED: Handler = (HashHandler*) Tokens->PreEval; if ((Handler->ContextRequired != CTX_NONE) && @@ -1176,6 +1327,8 @@ int EvaluateToken(StrBuf *Target, WCTemplateToken *Tokens, WCTemplate *pTmpl, vo return 0; } + + void ProcessTemplate(WCTemplate *Tmpl, StrBuf *Target, void *Context, int ContextType) { WCTemplate *pTmpl = Tmpl; @@ -1242,120 +1395,6 @@ void ProcessTemplate(WCTemplate *Tmpl, StrBuf *Target, void *Context, int Contex } } - -/** - * \brief Display a variable-substituted template - * \param templatename template file to load - */ -void *prepare_template(StrBuf *filename, StrBuf *Key, HashList *PutThere) -{ - WCTemplate *NewTemplate; - NewTemplate = (WCTemplate *) malloc(sizeof(WCTemplate)); - NewTemplate->Data = NULL; - NewTemplate->FileName = NewStrBufDup(filename); - NewTemplate->nTokensUsed = 0; - NewTemplate->TokenSpace = 0; - NewTemplate->Tokens = NULL; - - Put(PutThere, ChrPtr(Key), StrLength(Key), NewTemplate, FreeWCTemplate); - return NewTemplate; -} - -/** - * \brief Display a variable-substituted template - * \param templatename template file to load - */ -void *load_template(StrBuf *filename, StrBuf *Key, HashList *PutThere) -{ - int fd; - struct stat statbuf; - const char *pS, *pE, *pch, *Err; - long Line; - int pos; - WCTemplate *NewTemplate; - - fd = open(ChrPtr(filename), O_RDONLY); - if (fd <= 0) { - lprintf(1, "ERROR: could not open template '%s' - %s\n", - ChrPtr(filename), strerror(errno)); - return NULL; - } - - if (fstat(fd, &statbuf) == -1) { - lprintf(1, "ERROR: could not stat template '%s' - %s\n", - ChrPtr(filename), strerror(errno)); - return NULL; - } - - NewTemplate = (WCTemplate *) malloc(sizeof(WCTemplate)); - NewTemplate->Data = NewStrBufPlain(NULL, statbuf.st_size); - NewTemplate->FileName = NewStrBufDup(filename); - NewTemplate->nTokensUsed = 0; - NewTemplate->TokenSpace = 0; - NewTemplate->Tokens = NULL; - if (StrBufReadBLOB(NewTemplate->Data, &fd, 1, statbuf.st_size, &Err) < 0) { - close(fd); - FreeWCTemplate(NewTemplate); - lprintf(1, "ERROR: reading template '%s' - %s
\n", - ChrPtr(filename), strerror(errno)); - return NULL; - } - close(fd); - - Line = 0; - pS = pch = ChrPtr(NewTemplate->Data); - pE = pS + StrLength(NewTemplate->Data); - while (pch < pE) { - const char *pts, *pte; - int InQuotes = 0; - int InDoubleQuotes = 0; - - /** Find one */ - pos = (-1); - for (; pch < pE; pch ++) { - if ((*pch=='<')&&(*(pch + 1)=='?')) - break; - if (*pch=='\n') Line ++; - } - if (pch >= pE) - continue; - pts = pch; - - /** Found one? parse it. */ - for (; pch < pE - 1; pch ++) { - if (*pch == '"') - InDoubleQuotes = ! InDoubleQuotes; - else if (*pch == '\'') - InQuotes = ! InQuotes; - else if ((!InQuotes && !InDoubleQuotes) && - ((*pch!='\\')&&(*(pch + 1)=='>'))) { - pch ++; - break; - } - } - if (pch + 1 >= pE) - continue; - pte = pch; - PutNewToken(NewTemplate, - NewTemplateSubstitute(NewTemplate->Data, pS, pts, pte, Line, NewTemplate)); - pch ++; - } - if (LoadTemplates == 0) - Put(PutThere, ChrPtr(Key), StrLength(Key), NewTemplate, FreeWCTemplate); - return NewTemplate; -} - - -///void PrintTemplate(const char *Key, void *vSubst, int odd) -const char* PrintTemplate(void *vSubst) -{ - WCTemplate *Tmpl = vSubst; - - return ChrPtr(Tmpl->FileName); - -} - - /** * \brief Display a variable-substituted template * \param templatename template file to load @@ -1377,100 +1416,31 @@ void DoTemplate(const char *templatename, long len, StrBuf *Target, void *Contex StaticLocal = LocalTemplateCache; } - if (len == 0) - { - lprintf (1, "Can't to load a template with empty name!\n"); - StrBufAppendPrintf(Target, "
\nCan't to load a template with empty name!\n
"); - return; - } - - if (!GetHash(StaticLocal, templatename, len, &vTmpl) && - !GetHash(Static, templatename, len, &vTmpl)) { - lprintf (1, "didn't find Template [%s] %ld %ld\n", templatename, len , (long)strlen(templatename)); - StrBufAppendPrintf(Target, "
\ndidn't find Template [%s] %ld %ld\n
", - templatename, len, - (long)strlen(templatename)); -/// dbg_PrintHash(Static, PrintTemplate, NULL); -// PrintHash(Static, VarPrintTransition, PrintTemplate); - return; - } - if (vTmpl == NULL) - return; - ProcessTemplate(vTmpl, Target, Context, ContextType); -} - -int LoadTemplateDir(const char *DirName, HashList *wireless, HashList *big) -{ - StrBuf *FileName; - StrBuf *Tag; - StrBuf *Dir; - DIR *filedir = NULL; - struct dirent *filedir_entry; - int d_namelen; - int d_without_ext; - int IsMobile; - - Dir = NewStrBuf(); - StrBufPrintf(Dir, "%s/t", DirName); - filedir = opendir (ChrPtr(Dir)); - if (filedir == NULL) { - FreeStrBuf(&Dir); - return 0; - } - - FileName = NewStrBuf(); - Tag = NewStrBuf(); - while ((filedir_entry = readdir(filedir))) - { - char *MinorPtr; - char *PStart; -#ifdef _DIRENT_HAVE_D_NAMELEN - d_namelen = filedir_entry->d_namelen; -#else - d_namelen = strlen(filedir_entry->d_name); -#endif - d_without_ext = d_namelen; - while ((d_without_ext > 0) && (filedir_entry->d_name[d_without_ext] != '.')) - d_without_ext --; - if ((d_without_ext == 0) || (d_namelen < 3)) - continue; - if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~') - continue; /* Ignore backup files... */ - - IsMobile = (strstr(filedir_entry->d_name, ".m.html")!= NULL); - PStart = filedir_entry->d_name; - StrBufPrintf(FileName, "%s/%s", ChrPtr(Dir), filedir_entry->d_name); - MinorPtr = strchr(filedir_entry->d_name, '.'); - if (MinorPtr != NULL) - *MinorPtr = '\0'; - StrBufPlain(Tag, filedir_entry->d_name, MinorPtr - filedir_entry->d_name); - - if (LoadTemplates > 1) - lprintf(1, "%s %d %s\n",ChrPtr(FileName), IsMobile, ChrPtr(Tag)); - if (LoadTemplates == 0) - load_template(FileName, Tag, (IsMobile)?wireless:big); - else - prepare_template(FileName, Tag, (IsMobile)?wireless:big); + if (len == 0) + { + lprintf (1, "Can't to load a template with empty name!\n"); + StrBufAppendPrintf(Target, "
\nCan't to load a template with empty name!\n
"); + return; } - closedir(filedir); - FreeStrBuf(&FileName); - FreeStrBuf(&Tag); - FreeStrBuf(&Dir); - return 1; -} -void InitTemplateCache(void) -{ - LoadTemplateDir(static_dirs[0], - WirelessTemplateCache, - TemplateCache); - LoadTemplateDir(static_dirs[1], - WirelessLocalTemplateCache, - LocalTemplateCache); + if (!GetHash(StaticLocal, templatename, len, &vTmpl) && + !GetHash(Static, templatename, len, &vTmpl)) { + lprintf (1, "didn't find Template [%s] %ld %ld\n", templatename, len , (long)strlen(templatename)); + StrBufAppendPrintf(Target, "
\ndidn't find Template [%s] %ld %ld\n
", + templatename, len, + (long)strlen(templatename)); +/// dbg_PrintHash(Static, PrintTemplate, NULL); +// PrintHash(Static, VarPrintTransition, PrintTemplate); + return; + } + if (vTmpl == NULL) + return; + ProcessTemplate(vTmpl, Target, Context, ContextType); } - - +/*----------------------------------------------------------------------------- + * Iterators + */ typedef struct _HashIterator { HashList *StaticList; int AdditionalParams; @@ -1481,6 +1451,26 @@ typedef struct _HashIterator { SubTemplFunc DoSubTemplate; } HashIterator; +void RegisterITERATOR(const char *Name, long len, + int AdditionalParams, + HashList *StaticList, + RetrieveHashlistFunc GetHash, + SubTemplFunc DoSubTempl, + HashDestructorFunc Destructor, + int ContextType, + int XPectContextType) +{ + HashIterator *It = (HashIterator*)malloc(sizeof(HashIterator)); + It->StaticList = StaticList; + It->AdditionalParams = AdditionalParams; + It->GetHash = GetHash; + It->DoSubTemplate = DoSubTempl; + It->Destructor = Destructor; + It->ContextType = ContextType; + It->XPectContextType = XPectContextType; + Put(Iterators, Name, len, It, NULL); +} + void tmpl_iterate_subtmpl(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType) { void *vIt; @@ -1560,9 +1550,6 @@ void tmpl_iterate_subtmpl(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, vo } - - - if (It->StaticList == NULL) List = It->GetHash(Target, nArgs, Tokens, Context, ContextType); else @@ -1592,6 +1579,51 @@ void tmpl_iterate_subtmpl(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, vo It->Destructor(&List); } + + +/*----------------------------------------------------------------------------- + * Conditionals + */ +int EvaluateConditional(StrBuf *Target, WCTemplateToken *Tokens, WCTemplate *pTmpl, void *Context, int Neg, int state, int ContextType) +{ + ConditionalStruct *Cond; + + if ((Tokens->Params[0]->len == 1) && + (Tokens->Params[0]->Start[0] == 'X')) + return (state != 0)?Tokens->Params[1]->lvalue:0; + + Cond = (ConditionalStruct *) Tokens->PreEval; + if (Cond == NULL) { + lprintf(1, "Conditional [%s] (in '%s' line %ld); unknown![%s]\n", + Tokens->Params[0]->Start, + ChrPtr(pTmpl->FileName), + Tokens->Line, + ChrPtr(Tokens->FlatToken)); + return 1; + } + + if (Tokens->nParameters < Cond->nParams) { + lprintf(1, "Conditional [%s] (in '%s' line %ld); needs %ld Params![%s]\n", + Tokens->Params[0]->Start, + ChrPtr(pTmpl->FileName), + Tokens->Line, + Cond->nParams, + ChrPtr(Tokens->FlatToken)); + StrBufAppendPrintf( + Target, + "
\nConditional [%s] (in '%s' line %ld); needs %ld Params!\n[%s]\n
\n", + Tokens->Params[0]->Start, + ChrPtr(pTmpl->FileName), + Tokens->Line, + Cond->nParams, + ChrPtr(Tokens->FlatToken)); + return 0; + } + if (Cond->CondF(Tokens, Context, ContextType) == Neg) + return Tokens->Params[1]->lvalue; + return 0; +} + int ConditionalVar(WCTemplateToken *Tokens, void *Context, int ContextType) { void *vsubst; @@ -1632,25 +1664,6 @@ int ConditionalVar(WCTemplateToken *Tokens, void *Context, int ContextType) return 0; } -void RegisterITERATOR(const char *Name, long len, - int AdditionalParams, - HashList *StaticList, - RetrieveHashlistFunc GetHash, - SubTemplFunc DoSubTempl, - HashDestructorFunc Destructor, - int ContextType, - int XPectContextType) -{ - HashIterator *It = (HashIterator*)malloc(sizeof(HashIterator)); - It->StaticList = StaticList; - It->AdditionalParams = AdditionalParams; - It->GetHash = GetHash; - It->DoSubTemplate = DoSubTempl; - It->Destructor = Destructor; - It->ContextType = ContextType; - It->XPectContextType = XPectContextType; - Put(Iterators, Name, len, It, NULL); -} void RegisterConditional(const char *Name, long len, int nParams, @@ -1665,7 +1678,9 @@ void RegisterConditional(const char *Name, long len, Put(Conditionals, Name, len, Cond, NULL); } - +/*----------------------------------------------------------------------------- + * Context Strings + */ void tmplput_ContextString(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType) { StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, (StrBuf*)Context, 0); @@ -1680,6 +1695,9 @@ int ConditionalContextStr(WCTemplateToken *Tokens, void *Context, int ContextTyp return strcmp(ChrPtr(TokenText), CompareToken) == 0; } +/*----------------------------------------------------------------------------- + * Boxed-API + */ void tmpl_do_boxed(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType) { @@ -1711,9 +1729,12 @@ void tmpl_do_boxed(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Con Context, ContextType); DoTemplate(HKEY("endbox"), Target, Context, ContextType); - FreeStrBuf(Headline); + FreeStrBuf(&Headline); } +/*----------------------------------------------------------------------------- + * Tabbed-API + */ void tmpl_do_tabbed(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType) { @@ -1751,10 +1772,317 @@ void tmpl_do_tabbed(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Co } } + +/*----------------------------------------------------------------------------- + * Sorting-API + */ + +typedef struct _SortStruct { + StrBuf *Name; + StrBuf *PrefPrepend; + CompareFunc Forward; + CompareFunc Reverse; + + long ContextType; +}SortStruct; + +void DestroySortStruct(void *vSort) +{ + SortStruct *Sort = (SortStruct*) vSort; + FreeStrBuf(&Sort->Name); + FreeStrBuf(&Sort->PrefPrepend); + free (Sort); +} + +void RegisterSortFunc(const char *name, long len, + const char *prepend, long preplen, + CompareFunc Forward, + CompareFunc Reverse, + long ContextType) +{ + SortStruct *NewSort = (SortStruct*) malloc(sizeof(SortStruct)); + NewSort->Name = NewStrBufPlain(name, len); + if (prepend != NULL) + NewSort->PrefPrepend = NewStrBufPlain(prepend, preplen); + else + NewSort->PrefPrepend = NULL; + NewSort->Forward = Forward; + NewSort->Reverse = Reverse; + NewSort->ContextType = ContextType; + Put(SortHash, name, len, NewSort, DestroySortStruct); +} + +CompareFunc RetrieveSort(long ContextType, const char *OtherPrefix, + const char *Default, long ldefault, long DefaultDirection) +{ + int isdefault = 0; + const StrBuf *BSort; + SortStruct *SortBy; + void *vSortBy; + long SortOrder; + + if (havebstr("SortBy")) { + BSort = sbstr("SortBy"); + } + else { /** Try to fallback to our remembered values... */ + if (OtherPrefix == NULL) { + BSort = get_room_pref("sort"); + } + else { + ////todo: nail prefprepend to sort, and lookup this! + } + } + + if (!GetHash(SortHash, SKEY(BSort), &vSortBy) || + (vSortBy == NULL)) { + isdefault = 1; + if (!GetHash(SortHash, Default, ldefault, &vSortBy) || + (vSortBy == NULL)) { + lprintf(1, "Illegal default sort: [%s]\n", Default); + wc_backtrace(); + } + } + SortBy = (SortStruct*)vSortBy; + + /** Ok, its us, lets see in which direction we should sort... */ + if (havebstr("SortOrder")) { + SortOrder = LBSTR("SortOrder"); + } + else { /** Try to fallback to our remembered values... */ + if (SortBy->PrefPrepend == NULL) { + SortOrder = StrTol(get_room_pref("SortOrder")); + } + else { + ////todo: nail prefprepend to sort, and lookup this! + } + } + switch (SortOrder) { + default: + case 0: + return NULL; + case 1: + return SortBy->Forward; + case 2: + return SortBy->Reverse; + } +} + + +enum { + eNO_SUCH_SORT, + eNOT_SPECIFIED, + eINVALID_PARAM, + eFOUND +}; + +ConstStr SortIcons[] = { + {HKEY("static/sort_none.gif")}, + {HKEY("static/up_pointer.gif")}, + {HKEY("static/down_pointer.gif")}, +}; + +ConstStr SortNextOrder[] = { + {HKEY("1")}, + {HKEY("2")}, + {HKEY("0")}, +}; + + +int GetSortMetric(WCTemplateToken *Tokens, SortStruct **Next, SortStruct **Param, long *SortOrder) +{ + int bSortError = eNOT_SPECIFIED; + const StrBuf *BSort; + void *vSort; + + *SortOrder = 0; + *Next = NULL; + if (!GetHash(SortHash, Tokens->Params[0]->Start, Tokens->Params[0]->len, &vSort) || + (vSort == NULL)) + return eNO_SUCH_SORT; + *Param = (SortStruct*) vSort; + + + if (havebstr("SortBy")) { + BSort = sbstr("SortBy"); + bSortError = eINVALID_PARAM; + } + else { /** Try to fallback to our remembered values... */ + if ((*Param)->PrefPrepend == NULL) { + BSort = get_room_pref("sort"); + } + else { + ////todo: nail prefprepend to sort, and lookup this! + } + } + + if (!GetHash(SortHash, SKEY(BSort), &vSort) || + (vSort == NULL)) + return bSortError; + + *Next = (SortStruct*) vSort; + + /** Ok, its us, lets see in which direction we should sort... */ + if (havebstr("SortOrder")) { + *SortOrder = LBSTR("SortOrder"); + } + else { /** Try to fallback to our remembered values... */ + if ((*Param)->PrefPrepend == NULL) { + *SortOrder = StrTol(get_room_pref("SortOrder")); + } + else { + ////todo: nail prefprepend to sort, and lookup this! + } + } + if (*SortOrder > 2) + *SortOrder = 0; + + return eFOUND; +} + + +void tmplput_SORT_ICON(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType) +{ + long SortOrder; + SortStruct *Next; + SortStruct *Param; + const ConstStr *SortIcon; + + switch (GetSortMetric(Tokens, &Next, &Param, &SortOrder)){ + case eNO_SUCH_SORT: + lprintf(1, "[%s] (in '%s' line %ld); " + " Sorter [%s] unknown! [%s]\n", + Tokens->pName, + ChrPtr(Tokens->FileName), + Tokens->Line, + Tokens->Params[0]->Start, + ChrPtr(Tokens->FlatToken)); + StrBufAppendPrintf( + Target, + "
\n [%s] (in '%s' line %ld);"
+			" Sorter [%s] unknown!\n[%s]\n
\n", + Tokens->pName, + ChrPtr(Tokens->FileName), + Tokens->Line, + Tokens->Params[0]->Start, + ChrPtr(Tokens->FlatToken)); + break; + case eINVALID_PARAM: + lprintf(1, "[%s] (in '%s' line %ld); " + " Sorter specified by BSTR 'SortBy' [%s] unknown! [%s]\n", + Tokens->pName, + ChrPtr(Tokens->FileName), + Tokens->Line, + bstr("SortBy"), + ChrPtr(Tokens->FlatToken)); + case eNOT_SPECIFIED: + case eFOUND: + if (Next == Param) { + SortIcon = &SortIcons[SortOrder]; + } + else { /** Not Us... */ + SortIcon = &SortIcons[0]; + } + StrBufAppendBufPlain(Target, SortIcon->Key, SortIcon->len, 0); + } +} + +void tmplput_SORT_NEXT(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType) +{ + long SortOrder; + SortStruct *Next; + SortStruct *Param; + + switch (GetSortMetric(Tokens, &Next, &Param, &SortOrder)){ + case eNO_SUCH_SORT: + lprintf(1, "[%s] (in '%s' line %ld); " + " Sorter [%s] unknown! [%s]\n", + Tokens->pName, + ChrPtr(Tokens->FileName), + Tokens->Line, + Tokens->Params[0]->Start, + ChrPtr(Tokens->FlatToken)); + StrBufAppendPrintf( + Target, + "
\n [%s] (in '%s' line %ld);"
+			" Sorter [%s] unknown!\n[%s]\n
\n", + Tokens->pName, + ChrPtr(Tokens->FileName), + Tokens->Line, + Tokens->Params[0]->Start, + ChrPtr(Tokens->FlatToken)); + break; + case eINVALID_PARAM: + lprintf(1, "[%s] (in '%s' line %ld); " + " Sorter specified by BSTR 'SortBy' [%s] unknown! [%s]\n", + Tokens->pName, + ChrPtr(Tokens->FileName), + Tokens->Line, + bstr("SortBy"), + ChrPtr(Tokens->FlatToken)); + + case eNOT_SPECIFIED: + case eFOUND: + StrBufAppendBuf(Target, Param->Name, 0); + + } +} + +void tmplput_SORT_ORDER(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType) +{ + long SortOrder; + const ConstStr *SortOrderStr; + SortStruct *Next; + SortStruct *Param; + + switch (GetSortMetric(Tokens, &Next, &Param, &SortOrder)){ + case eNO_SUCH_SORT: + lprintf(1, "[%s] (in '%s' line %ld); " + " Sorter [%s] unknown! [%s]\n", + Tokens->pName, + ChrPtr(Tokens->FileName), + Tokens->Line, + Tokens->Params[0]->Start, + ChrPtr(Tokens->FlatToken)); + StrBufAppendPrintf( + Target, + "
\n [%s] (in '%s' line %ld);"
+			" Sorter [%s] unknown!\n[%s]\n
\n", + Tokens->pName, + ChrPtr(Tokens->FileName), + Tokens->Line, + Tokens->Params[0]->Start, + ChrPtr(Tokens->FlatToken)); + break; + case eINVALID_PARAM: + lprintf(1, "[%s] (in '%s' line %ld); " + " Sorter specified by BSTR 'SortBy' [%s] unknown! [%s]\n", + Tokens->pName, + ChrPtr(Tokens->FileName), + Tokens->Line, + bstr("SortBy"), + ChrPtr(Tokens->FlatToken)); + + case eNOT_SPECIFIED: + case eFOUND: + if (Next == Param) { + SortOrderStr = &SortNextOrder[SortOrder]; + } + else { /** Not Us... */ + SortOrderStr = &SortNextOrder[0]; + } + StrBufAppendBufPlain(Target, SortOrderStr->Key, SortOrderStr->len, 0); + } +} + + + void InitModule_SUBST (void) { + RegisterNamespace("SORT:ICON", 1, 1, tmplput_SORT_ICON, CTX_NONE); + RegisterNamespace("SORT:ORDER", 1, 1, tmplput_SORT_ORDER, CTX_NONE); + RegisterNamespace("SORT:NEXT", 1, 1, tmplput_SORT_NEXT, CTX_NONE); RegisterNamespace("CONTEXTSTR", 0, 1, tmplput_ContextString, CTX_STRBUF); RegisterNamespace("ITERATE", 2, 100, tmpl_iterate_subtmpl, CTX_NONE); RegisterNamespace("DOBOXED", 1, 2, tmpl_do_boxed, CTX_NONE); diff --git a/webcit/webcit.h b/webcit/webcit.h index f431ac9e7..4e2e3f016 100644 --- a/webcit/webcit.h +++ b/webcit/webcit.h @@ -387,7 +387,13 @@ void StrBufAppendTemplate(StrBuf *Target, WCTemplateToken *Tokens, void *Context, int ContextType, const StrBuf *Source, int FormatTypeIndex); - +CompareFunc RetrieveSort(long ContextType, const char *OtherPrefix, + const char *Default, long ldefault, long DefaultDirection); +void RegisterSortFunc(const char *name, long len, + const char *prepend, long preplen, + CompareFunc Forward, + CompareFunc Reverse, + long ContextType); /* @@ -474,6 +480,7 @@ typedef struct _message_summary { wc_mime_attachment *MsgBody; } message_summary; void DestroyMessageSummary(void *vMsg); +inline message_summary* GetMessagePtrAt(int n, HashList *Summ); typedef void (*ExamineMsgHeaderFunc)(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset); @@ -579,7 +586,6 @@ struct wcsession { int killthis; /**< Nonzero == purge this session */ struct march *march; /**< march mode room list */ char reply_to[512]; /**< reply-to address */ - long msgarr[10000]; /**< for read operations */ HashList *summ; /**< list of messages for mailbox summary view */ int is_mobile; /**< Client is a handheld browser */ HashList *urlstrings; /**< variables passed to webcit in a URL */ @@ -692,6 +698,7 @@ extern HashList *ZoneHash; extern HashList *Conditionals; extern HashList *MsgHeaderHandler; extern HashList *MimeRenderHandler; +extern HashList *SortHash; void InitialiseSemaphores(void); void begin_critical_section(int which_one); diff --git a/webcit/webserver.c b/webcit/webserver.c index 4b8a28c9b..376ea44c5 100644 --- a/webcit/webserver.c +++ b/webcit/webserver.c @@ -696,6 +696,7 @@ int main(int argc, char **argv) Conditionals = NewHash(1, NULL); MsgHeaderHandler = NewHash(1, NULL); MimeRenderHandler = NewHash(1, NULL); + SortHash = NewHash(1, NULL); LoadZoneFiles(); @@ -982,6 +983,7 @@ void ShutDownWebcit(void) DeleteHash(&MimeRenderHandler); DeleteHash(&Conditionals); DeleteHash(&MsgHeaderHandler); + DeleteHash(&SortHash); #ifdef ENABLE_NLS ShutdownLocale(); #endif -- 2.30.2