From 5c67cc635952963d041472aaca778106522797ab Mon Sep 17 00:00:00 2001 From: =?utf8?q?Wilfried=20G=C3=B6esgens?= Date: Sat, 27 Dec 2008 23:19:17 +0000 Subject: [PATCH] * add first draft of group-change detection * templatize downloads --- webcit/downloads.c | 479 +++++++----------- webcit/inetconf.c | 2 +- webcit/msg_renderers.c | 53 +- webcit/netconf.c | 2 +- webcit/preferences.c | 6 +- webcit/pushemail.c | 4 +- webcit/roomops.c | 2 +- webcit/static/t/files.html | 50 ++ webcit/static/t/files_jspicview.html | 22 + webcit/static/t/menu_basic_commands.html | 2 +- webcit/static/t/section_files_onefile.html | 21 + .../t/section_files_onefile_picview.html | 3 + webcit/subst.c | 72 ++- webcit/subst.h | 11 +- webcit/useredit.c | 2 +- webcit/who.c | 2 +- 16 files changed, 402 insertions(+), 331 deletions(-) create mode 100644 webcit/static/t/files.html create mode 100644 webcit/static/t/files_jspicview.html create mode 100644 webcit/static/t/section_files_onefile.html create mode 100644 webcit/static/t/section_files_onefile_picview.html diff --git a/webcit/downloads.c b/webcit/downloads.c index 4706d0042..b5052d82e 100644 --- a/webcit/downloads.c +++ b/webcit/downloads.c @@ -4,19 +4,57 @@ #include "webcit.h" #include "webserver.h" +extern char* static_dirs[]; + typedef struct _FileListStruct { - char Filename[256]; - int FilenameLen; + StrBuf *Filename; long FileSize; - char MimeType[64]; - int MimeTypeLen; - char Comment[512]; - int CommentLen; + StrBuf *MimeType; + StrBuf *Comment; int IsPic; int Sequence; -}FileListStruct; +} FileListStruct; + +void FreeFiles(void *vFile) +{ + FileListStruct *F = (FileListStruct*) vFile; + FreeStrBuf(&F->Filename); + FreeStrBuf(&F->MimeType); + FreeStrBuf(&F->Comment); + free(F); +} + +/* -------------------------------------------------------------------------------- */ +void tmplput_FILE_NAME(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType) +{ + FileListStruct *F = (FileListStruct*) Context; + StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, F->Filename, 0); +} +void tmplput_FILE_SIZE(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType) +{ + FileListStruct *F = (FileListStruct*) Context; + StrBufAppendPrintf(Target, "%ld", F->FileSize); +} +void tmplput_FILEMIMETYPE(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType) +{ + FileListStruct *F = (FileListStruct*) Context; + StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, F->MimeType, 0); +} +void tmplput_FILE_COMMENT(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType) +{ + FileListStruct *F = (FileListStruct*) Context; + StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, F->Comment, 0); +} +/* -------------------------------------------------------------------------------- */ +int Conditional_FILE_ISPIC(WCTemplateToken *Tokens, void *Context, int ContextType) +{ + FileListStruct *F = (FileListStruct*) Context; + return F->IsPic; +} + +/* -------------------------------------------------------------------------------- */ int CompareFilelistByMime(const void *vFile1, const void *vFile2) { FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1); @@ -24,7 +62,7 @@ int CompareFilelistByMime(const void *vFile1, const void *vFile2) if (File1->IsPic != File2->IsPic) return File1->IsPic > File2->IsPic; - return strcasecmp(File1->MimeType, File2->MimeType); + return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType)); } int CompareFilelistByMimeRev(const void *vFile1, const void *vFile2) { @@ -32,9 +70,45 @@ int CompareFilelistByMimeRev(const void *vFile1, const void *vFile2) FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2); if (File1->IsPic != File2->IsPic) return File1->IsPic < File2->IsPic; - return strcasecmp(File2->MimeType, File1->MimeType); + return strcasecmp(ChrPtr(File2->MimeType), ChrPtr(File1->MimeType)); +} +int GroupchangeFilelistByMime(const void *vFile1, const void *vFile2) +{ + FileListStruct *File1 = (FileListStruct*) vFile1; + FileListStruct *File2 = (FileListStruct*) vFile2; + + if (File1->IsPic != File2->IsPic) + return File1->IsPic > File2->IsPic; + return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType)) != 0; } + +int CompareFilelistByName(const void *vFile1, const void *vFile2) +{ + FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1); + FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2); + + if (File1->IsPic != File2->IsPic) + return File1->IsPic > File2->IsPic; + return strcasecmp(ChrPtr(File1->Filename), ChrPtr(File2->Filename)); +} +int CompareFilelistByNameRev(const void *vFile1, const void *vFile2) +{ + FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1); + FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2); + if (File1->IsPic != File2->IsPic) + return File1->IsPic < File2->IsPic; + return strcasecmp(ChrPtr(File2->Filename), ChrPtr(File1->Filename)); +} +int GroupchangeFilelistByName(const void *vFile1, const void *vFile2) +{ + FileListStruct *File1 = (FileListStruct*) vFile1; + FileListStruct *File2 = (FileListStruct*) vFile2; + + return ChrPtr(File1->Filename)[0] != ChrPtr(File2->Filename)[0]; +} + + int CompareFilelistBySize(const void *vFile1, const void *vFile2) { FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1); @@ -43,7 +117,6 @@ int CompareFilelistBySize(const void *vFile1, const void *vFile2) return 0; return (File1->FileSize > File2->FileSize); } - int CompareFilelistBySizeRev(const void *vFile1, const void *vFile2) { FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1); @@ -52,19 +125,31 @@ int CompareFilelistBySizeRev(const void *vFile1, const void *vFile2) return 0; return (File1->FileSize < File2->FileSize); } +int GroupchangeFilelistBySize(const void *vFile1, const void *vFile2) +{ + return 0; +} + int CompareFilelistByComment(const void *vFile1, const void *vFile2) { FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1); FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2); - return strcasecmp(File1->Comment, File2->Comment); + return strcasecmp(ChrPtr(File1->Comment), ChrPtr(File2->Comment)); } int CompareFilelistByCommentRev(const void *vFile1, const void *vFile2) { FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1); FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2); - return strcasecmp(File2->Comment, File1->Comment); + return strcasecmp(ChrPtr(File2->Comment), ChrPtr(File1->Comment)); } +int GroupchangeFilelistByComment(const void *vFile1, const void *vFile2) +{ + FileListStruct *File1 = (FileListStruct*) vFile1; + FileListStruct *File2 = (FileListStruct*) vFile2; + return ChrPtr(File1->Comment)[9] != ChrPtr(File2->Comment)[0]; +} + int CompareFilelistBySequence(const void *vFile1, const void *vFile2) { @@ -72,298 +157,67 @@ int CompareFilelistBySequence(const void *vFile1, const void *vFile2) FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2); return (File2->Sequence > File1->Sequence); } +int GroupchangeFilelistBySequence(const void *vFile1, const void *vFile2) +{ + return 0; +} -HashList* LoadFileList(int *HavePic) +/* -------------------------------------------------------------------------------- */ +HashList* LoadFileList(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType) { FileListStruct *Entry; + StrBuf *Buf; HashList *Files; - int HavePics = 0; - int Order; + int Done = 0; int sequence = 0; char buf[1024]; + CompareFunc SortIt; + int HavePic; serv_puts("RDIR"); serv_getln(buf, sizeof buf); - if (buf[0] == '1') { - Files = NewHash(1, NULL); - while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) - { - Entry = (FileListStruct*) malloc(sizeof (FileListStruct)); - - Entry->FilenameLen = extract_token( - Entry->Filename, buf, 0, '|', - sizeof(Entry->Filename)); - Entry->FileSize = extract_long(buf, 1); - Entry->MimeTypeLen = extract_token( - Entry->MimeType, buf, 2, '|', - sizeof(Entry->MimeType)); - Entry->CommentLen = extract_token( - Entry->Comment, buf, 3, '|', - sizeof(Entry->Comment)); - - Entry->Sequence = sequence++; - Entry->IsPic = (strstr(Entry->MimeType, "image") != NULL); - if (!HavePics && Entry->IsPic) { - HavePics = 1; - *HavePic = 1; - } - Put(Files, Entry->Filename, - Entry->FilenameLen, - Entry, NULL); - } - Order = ibstr("SortOrder"); - switch (ibstr("SortBy")){ - case 1: /*NAME*/ - SortByHashKey(Files,Order); - break; - case 2: /* SIZE*/ - SortByPayload(Files, (Order)? - CompareFilelistBySize: - CompareFilelistBySizeRev); - break; - case 3: /*MIME*/ - SortByPayload(Files, (Order)? - CompareFilelistByMime: - CompareFilelistByMimeRev); - break; - case 4: /*COMM*/ - SortByPayload(Files, (Order)? - CompareFilelistByComment: - CompareFilelistByCommentRev); - break; - default: - SortByPayload(Files, CompareFilelistBySequence); - } - return Files; - } - else - return NULL; -} - -void FilePrintEntry(const char *FileName, void *vFile, int odd) -{ - FileListStruct *File = (FileListStruct*) vFile; - - wprintf("", (odd ? "DDDDDD" : "FFFFFF")); - wprintf("" - "Filename); - wprintf("\">\n", - File->MimeType); - escputs(File->Filename); wprintf(""); - wprintf("%ld", File->FileSize); - wprintf(""); escputs(File->MimeType); wprintf(""); - wprintf(""); escputs(File->Comment); wprintf(""); - wprintf("\n"); -} + if (buf[0] != '1') return NULL; -void FilePrintTransition(void *vFile1, void *vFile2, int odd) -{ - FileListStruct *File1 = (FileListStruct*) vFile1; - FileListStruct *File2 = (FileListStruct*) vFile2; - char StartChar[2] = "\0\0"; - char *SectionName; - - switch (ibstr("SortBy")){ - case 1: /*NAME*/ - if ((File2 != NULL) && - ((File1 == NULL) || - (File1->Filename[0] != File2->Filename[0]))) { - StartChar[0] = File2->Filename[0]; - SectionName = StartChar; + Buf = NewStrBuf(); + Files = NewHash(1, NULL); + while (!Done && (StrBuf_ServGetln(Buf)>=0)) { + if ( (StrLength(Buf)==3) && + !strcmp(ChrPtr(Buf), "000")) + { + Done = 1; + continue; } - else return; - break; - case 2: /* SIZE*/ - return; - case 3: /*MIME*/ - return; /*TODO*/ - break; - case 4: /*COMM*/ - return; - default: - return; - } - - wprintf("%s", - (odd ? "DDDDDD" : "FFFFFF"), SectionName); -} + Entry = (FileListStruct*) malloc(sizeof (FileListStruct)); + Entry->Filename = NewStrBufPlain(NULL, StrLength(Buf)); + Entry->MimeType = NewStrBufPlain(NULL, StrLength(Buf)); + Entry->Comment = NewStrBufPlain(NULL, StrLength(Buf)); -void display_room_directory(void) -{ - char title[256]; - int havepics = 0; - HashList *Files; - int Order; - int SortRow; - int i; - - long SortDirections[5] = {2,2,2,2,2}; - const char* SortIcons[3] = { - "static/up_pointer.gif", - "static/down_pointer.gif", - "static/sort_none.gif"}; - char *RowNames[5]; - RowNames[0] = ""; - RowNames[1] = _("Filename"); - RowNames[2] = _("Size"); - RowNames[3] = _("Content"); - RowNames[4] = _("Description"); - - Files = LoadFileList (&havepics); - output_headers(1, 1, 2, 0, 0, 0); - wprintf("
\n"); - wprintf("

"); - snprintf(title, sizeof title, _("Files available for download in %s"), WC->wc_roomname); - escputs(title); - wprintf("

"); - wprintf("
\n"); - - wprintf("
\n"); - - wprintf("
" - "\n"); - for (i = 1; i < 5; i++) { - switch (SortDirections[i]) { - default: - case 0: - Order = 2; - break; - case 1: - Order = 0; - break; - case 2: - Order = 1; - break; - } - - wprintf(" \n", - RowNames[i], - Order, i, - SortIcons[SortDirections[i]] - ); + Entry->Sequence = sequence++; - } - wprintf("\n"); -//\n", - //); + StrBufExtract_token(Entry->Filename, Buf, 0, '|'); + Entry->FileSize = StrBufExtract_long(Buf, 1, '|'); + StrBufExtract_token(Entry->MimeType, Buf, 2, '|'); + StrBufExtract_token(Entry->Comment, Buf, 3, '|'); - if (Files != NULL) { - PrintHash(Files, FilePrintTransition, FilePrintEntry); - DeleteHash(&Files); - } - wprintf("
\n"); - - - Order = ibstr("SortOrder"); - if (!havebstr("SortOrder") || Order > 2) - Order = 2; /* <- Unsorted... */ - SortRow = ibstr("SortBy"); - - SortDirections[SortRow] = Order; - - wprintf("
%s \n" - " \n" - " \n" - "
%s%s%s%s
\n"); - /** Now offer the ability to upload files... */ - if (WC->room_flags & QR_UPLOAD) - { - wprintf("
"); - wprintf("
\n" - ); - wprintf("\n", WC->nonce); - - wprintf(_("Upload a file:")); - wprintf("  \n"); - wprintf(_("Description:")); - wprintf("  "); - wprintf("\n", _("Upload")); - - wprintf("
\n"); - } - wprintf("
\n"); - if (havepics) - wprintf("", _("Slideshow")); - wDumpContent(1); -} - - -void display_pictureview(void) -{ - char buf[1024]; - char filename[256]; - char filesize[256]; - char mimetype[64]; - char comment[512]; - char title[256]; - int n = 0; - - - if (lbstr("frame") == 1) { - - output_headers(1, 1, 2, 0, 0, 0); - wprintf("
\n"); - wprintf("

"); - snprintf(title, sizeof title, _("Pictures in %s"), WC->wc_roomname); - escputs(title); - wprintf("

"); - wprintf("
\n"); - - wprintf("
\n"); - - wprintf("
" - "
\n"); - - - - wprintf("\n"); - wprintf("
\n"); - wprintf("\n"); - wprintf("\n"); + Entry->IsPic = (strstr(ChrPtr(Entry->MimeType), "image") != NULL); + if (Entry->IsPic) { + HavePic = 1; + } + Put(Files, SKEY(Entry->Filename), Entry, FreeFiles); } - wDumpContent(1); - - + SortIt = RetrieveSort(CTX_FILELIST, NULL, HKEY("fileunsorted"), 0); + if (SortIt != NULL) + SortByPayload(Files, SortIt); + else + SortByPayload(Files, CompareFilelistBySequence); + FreeStrBuf(&Buf); + svputlong("FILE:HAVEPICS", HavePic); + return Files; } -extern char* static_dirs[]; void display_mime_icon(void) { char FileBuf[SIZ]; @@ -379,7 +233,6 @@ void display_mime_icon(void) else snprintf (FileBuf, SIZ, "%s%s", static_dirs[3], FileName); output_static(FileBuf); - } void download_file(void) @@ -418,7 +271,6 @@ void download_file(void) wprintf(_("An error occurred while retrieving this file: %s\n"), &buf[4]); end_burst(); } - } @@ -437,7 +289,7 @@ void upload_file(void) if (buf[0] != '2') { strcpy(WCC->ImportantMessage, &buf[4]); - display_room_directory(); + do_template("files", NULL); return; } @@ -461,7 +313,7 @@ void upload_file(void) serv_puts("UCLS 1"); serv_getln(buf, sizeof buf); strcpy(WCC->ImportantMessage, &buf[4]); - display_room_directory(); + do_template("files", CTX_NONE); } @@ -470,7 +322,7 @@ void upload_file(void) * When the browser requests an image file from the Citadel server, * this function is called to transmit it. */ -void output_image() +void output_image(void) { char blank_gif[SIZ]; wcsession *WCC = WC; @@ -509,18 +361,55 @@ void output_image() output_static(blank_gif); } - - - void InitModule_DOWNLOAD (void) { + + RegisterIterator("ROOM:FILES", 0, NULL, LoadFileList, + NULL,NULL, CTX_FILELIST, CTX_NONE, + IT_FLAG_DETECT_GROUPCHANGE); + + RegisterSortFunc(HKEY("filemime"), + NULL, 0, + CompareFilelistByMime, + CompareFilelistByMimeRev, + GroupchangeFilelistByMime, + CTX_FILELIST); + RegisterSortFunc(HKEY("filename"), + NULL, 0, + CompareFilelistByName, + CompareFilelistByNameRev, + GroupchangeFilelistByName, + CTX_FILELIST); + RegisterSortFunc(HKEY("filesize"), + NULL, 0, + CompareFilelistBySize, + CompareFilelistBySizeRev, + GroupchangeFilelistBySize, + CTX_FILELIST); + RegisterSortFunc(HKEY("filesubject"), + NULL, 0, + CompareFilelistByComment, + CompareFilelistByCommentRev, + GroupchangeFilelistByComment, + CTX_FILELIST); + RegisterSortFunc(HKEY("fileunsorted"), + NULL, 0, + CompareFilelistBySequence, + CompareFilelistBySequence, + GroupchangeFilelistBySequence, + CTX_FILELIST); + + RegisterNamespace("FILE:NAME", 0, 2, tmplput_FILE_NAME, CTX_FILELIST); + RegisterNamespace("FILE:SIZE", 0, 1, tmplput_FILE_SIZE, CTX_FILELIST); + RegisterNamespace("FILE:MIMETYPE", 0, 2, tmplput_FILEMIMETYPE, CTX_FILELIST); + RegisterNamespace("FILE:COMMENT", 0, 2, tmplput_FILE_COMMENT, CTX_FILELIST); + + RegisterConditional(HKEY("COND:FILE:ISPIC"), 0, Conditional_FILE_ISPIC, CTX_FILELIST); + WebcitAddUrlHandler(HKEY("image"), output_image, 0); WebcitAddUrlHandler(HKEY("display_mime_icon"), display_mime_icon , 0); - - WebcitAddUrlHandler(HKEY("display_room_directory"), display_room_directory, 0); - WebcitAddUrlHandler(HKEY("display_pictureview"), display_pictureview, 0); WebcitAddUrlHandler(HKEY("download_file"), download_file, NEED_URL); WebcitAddUrlHandler(HKEY("upload_file"), upload_file, 0); } diff --git a/webcit/inetconf.c b/webcit/inetconf.c index f50a045bd..97820b7ab 100644 --- a/webcit/inetconf.c +++ b/webcit/inetconf.c @@ -207,6 +207,6 @@ InitModule_INETCONF (void) { WebcitAddUrlHandler(HKEY("save_inetconf"), new_save_inetconf, AJAX); - RegisterIterator("SERVCFG:INET", 1, NULL, GetInetConfHash, InetCfgSubst, NULL, CTX_INETCFG, CTX_NONE); + RegisterIterator("SERVCFG:INET", 1, NULL, GetInetConfHash, InetCfgSubst, NULL, CTX_INETCFG, CTX_NONE, IT_NOFLAG); RegisterNamespace("SERVCFG:FLUSHINETCFG",0, 0, DeleteInetConfHash, CTX_NONE); } diff --git a/webcit/msg_renderers.c b/webcit/msg_renderers.c index abf6b55e4..6ac25d56a 100644 --- a/webcit/msg_renderers.c +++ b/webcit/msg_renderers.c @@ -124,6 +124,17 @@ int summcmp_rsubj(const void *s1, const void *s2) { summ2 = (message_summary *)GetSearchPayload(s2); return strcasecmp(ChrPtr(summ2->subj), ChrPtr(summ1->subj)); } +/* + * comparator for message summary structs by descending subject. + */ +int groupchange_subj(const void *s1, const void *s2) { + message_summary *summ1; + message_summary *summ2; + + summ1 = (message_summary *)s1; + summ2 = (message_summary *)s2; + return ChrPtr(summ2->subj)[0] != ChrPtr(summ1->subj)[0]; +} /* * comparator for message summary structs by ascending sender. @@ -148,6 +159,18 @@ int summcmp_rsender(const void *s1, const void *s2) { summ2 = (message_summary *)GetSearchPayload(s2); return strcasecmp(ChrPtr(summ2->from), ChrPtr(summ1->from)); } +/* + * comparator for message summary structs by descending sender. + */ +int groupchange_sender(const void *s1, const void *s2) { + message_summary *summ1; + message_summary *summ2; + + summ1 = (message_summary *)s1; + summ2 = (message_summary *)s2; + return strcasecmp(ChrPtr(summ2->from), ChrPtr(summ1->from)) != 0; + +} /* * comparator for message summary structs by ascending date. @@ -179,6 +202,21 @@ int summcmp_rdate(const void *s1, const void *s2) { else return 0; } +/* + * comparator for message summary structs by descending date. + */ +const long DAYSECONDS = 24 * 60 * 60; +int groupchange_date(const void *s1, const void *s2) { + message_summary *summ1; + message_summary *summ2; + + summ1 = (message_summary *)s1; + summ2 = (message_summary *)s2; + + return (summ1->date % DAYSECONDS) != (summ2->date %DAYSECONDS); +} + + /*----------------------------------------------------------------------------*/ /* Don't wanna know... or? */ void examine_pref(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset) {return;} @@ -1012,21 +1050,24 @@ InitModule_MSGRENDERERS NULL, 0, summcmp_date, summcmp_rdate, + groupchange_date, CTX_MAILSUM); RegisterSortFunc(HKEY("subject"), NULL, 0, summcmp_subj, summcmp_rsubj, + groupchange_subj, CTX_MAILSUM); RegisterSortFunc(HKEY("sender"), NULL, 0, summcmp_sender, summcmp_rsender, + groupchange_sender, CTX_MAILSUM); /* iterate over all known mails in WC->summ */ RegisterIterator("MAIL:SUMM:MSGS", 0, NULL, iterate_get_mailsumm_All, - NULL,NULL, CTX_MAILSUM, CTX_NONE); + NULL,NULL, CTX_MAILSUM, CTX_NONE, IT_NOFLAG); /* render parts of the message struct */ RegisterNamespace("MAIL:SUMM:DATESTR", 0, 0, tmplput_MAIL_SUMM_DATE_STR, CTX_MAILSUM); @@ -1060,13 +1101,13 @@ InitModule_MSGRENDERERS RegisterConditional(HKEY("COND:MAIL:MIME:ATTACH:LINKS"), 0, Conditional_MAIL_MIME_ATTACHLINKS, CTX_MAILSUM); RegisterConditional(HKEY("COND:MAIL:MIME:ATTACH:ATT"), 0, Conditional_MAIL_MIME_ATTACH, CTX_MAILSUM); RegisterIterator("MAIL:MIME:ATTACH", 0, NULL, iterate_get_mime_All, - NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM); + NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM, IT_NOFLAG); RegisterIterator("MAIL:MIME:ATTACH:SUBMESSAGES", 0, NULL, iterate_get_mime_Submessages, - NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM); + NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM, IT_NOFLAG); RegisterIterator("MAIL:MIME:ATTACH:LINKS", 0, NULL, iterate_get_mime_AttachLinks, - NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM); + NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM, IT_NOFLAG); RegisterIterator("MAIL:MIME:ATTACH:ATT", 0, NULL, iterate_get_mime_Attachments, - NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM); + NULL, NULL, CTX_MIME_ATACH, CTX_MAILSUM, IT_NOFLAG); /* Parts of a mime attachent */ RegisterNamespace("MAIL:MIME:NAME", 0, 2, tmplput_MIME_Name, CTX_MIME_ATACH); @@ -1083,7 +1124,7 @@ InitModule_MSGRENDERERS /* iterate the WC->attachments; use the above tokens for their contents */ RegisterIterator("MSG:ATTACHNAMES", 0, NULL, iterate_get_registered_Attachments, - NULL, NULL, CTX_MIME_ATACH, CTX_NONE); + NULL, NULL, CTX_MIME_ATACH, CTX_NONE, IT_NOFLAG); /* mime renderers translate an attachment into webcit viewable html text */ RegisterMimeRenderer(HKEY("message/rfc822"), render_MAIL); diff --git a/webcit/netconf.c b/webcit/netconf.c index d95c6ea5e..456b7f6c7 100644 --- a/webcit/netconf.c +++ b/webcit/netconf.c @@ -282,6 +282,6 @@ InitModule_NETCONF WebcitAddUrlHandler(HKEY("display_netconf"), display_netconf, 0); WebcitAddUrlHandler(HKEY("display_confirm_delete_node"), display_confirm_delete_node, 0); WebcitAddUrlHandler(HKEY("delete_node"), delete_node, 0); - RegisterIterator("NODECONFIG", 0, NULL, load_netconf, NodeCfgSubst, DeleteHash, CTX_NODECONF, CTX_NONE); + RegisterIterator("NODECONFIG", 0, NULL, load_netconf, NodeCfgSubst, DeleteHash, CTX_NODECONF, CTX_NONE, IT_NOFLAG); } /*@}*/ diff --git a/webcit/preferences.c b/webcit/preferences.c index b66a3bd38..a2efb4402 100644 --- a/webcit/preferences.c +++ b/webcit/preferences.c @@ -606,15 +606,15 @@ InitModule_PREFERENCES RegisterNamespace("PREF:VALUE", 1, 2, tmplput_CFG_Value, CTX_NONE); RegisterNamespace("PREF:DESCR", 1, 1, tmplput_CFG_Descr, CTX_NONE); - RegisterIterator("PREF:ZONE", 0, ZoneHash, NULL, CfgZoneTempl, NULL, CTX_PREF, CTX_NONE); + RegisterIterator("PREF:ZONE", 0, ZoneHash, NULL, CfgZoneTempl, NULL, CTX_PREF, CTX_NONE, IT_NOFLAG); RegisterConditional(HKEY("COND:PREF"), 4, ConditionalPreference, CTX_NONE); RegisterConditional(HKEY("COND:PREF:SET"), 4, ConditionalHazePreference, CTX_NONE); RegisterIterator("PREF:VALID:EMAIL:ADDR", 0, NULL, - GetGVEAHash, NULL, DeleteGVEAHash, CTX_STRBUF, CTX_NONE); + GetGVEAHash, NULL, DeleteGVEAHash, CTX_STRBUF, CTX_NONE, IT_NOFLAG); RegisterIterator("PREF:VALID:EMAIL:NAME", 0, NULL, - GetGVSNHash, NULL, DeleteGVSNHash, CTX_STRBUF, CTX_NONE); + GetGVSNHash, NULL, DeleteGVSNHash, CTX_STRBUF, CTX_NONE, IT_NOFLAG); } /*@}*/ diff --git a/webcit/pushemail.c b/webcit/pushemail.c index d4e06bed5..3346d83ba 100644 --- a/webcit/pushemail.c +++ b/webcit/pushemail.c @@ -30,10 +30,10 @@ void display_pushemail(void) { serv_printf("MSG0 %d", msgnum); serv_getln(buf, sizeof buf); if (buf[0] == '1') { + int i =0; while (serv_getln(buf, sizeof buf), (strcmp(buf, "text") && strcmp(buf, "000"))) { } - int i =0; if (!strcmp(buf, "text")) { while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { if (strncasecmp(buf, "none", 4) == 0) { @@ -64,7 +64,7 @@ void display_pushemail(void) { } output_headers(1, 1, 2, 0, 0, 0); do_template("pushemail", NULL); -//do_template("endbox"); +/*do_template("endbox"); */ wDumpContent(1); } diff --git a/webcit/roomops.c b/webcit/roomops.c index 4c47999e4..1e20e12a1 100644 --- a/webcit/roomops.c +++ b/webcit/roomops.c @@ -489,7 +489,7 @@ void embed_room_banner(char *got, int navbar_style) { if (buf2[0] == '1') while (serv_getln(buf2, sizeof buf2), strcmp(buf2, "000")) file_count++; snprintf (with_files, sizeof with_files, - "; %d %s ", + "; %d %s ", file_count, ((file_count>1) || (file_count == 0) ? _("files") : _("file"))); } diff --git a/webcit/static/t/files.html b/webcit/static/t/files.html new file mode 100644 index 000000000..a4aecbabc --- /dev/null +++ b/webcit/static/t/files.html @@ -0,0 +1,50 @@ + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + +  +  +  +  +"> + + + + + + + + + diff --git a/webcit/static/t/files_jspicview.html b/webcit/static/t/files_jspicview.html new file mode 100644 index 000000000..72ecb6e35 --- /dev/null +++ b/webcit/static/t/files_jspicview.html @@ -0,0 +1,22 @@ + + + + + +
+
+
 &SortBy=">" />  &SortBy=">" />  &SortBy=">" />  &SortBy=">" />
+ + + + + + + + + + +
+ +
+ + + diff --git a/webcit/static/t/menu_basic_commands.html b/webcit/static/t/menu_basic_commands.html index 79efe1372..7dcf179ca 100644 --- a/webcit/static/t/menu_basic_commands.html +++ b/webcit/static/t/menu_basic_commands.html @@ -10,7 +10,7 @@
  • and new")>
  • -
  • +
    • diff --git a/webcit/static/t/section_files_onefile.html b/webcit/static/t/section_files_onefile.html new file mode 100644 index 000000000..76d052135 --- /dev/null +++ b/webcit/static/t/section_files_onefile.html @@ -0,0 +1,21 @@ + +
    + "> + + +
    + +
    + + diff --git a/webcit/static/t/section_files_onefile_picview.html b/webcit/static/t/section_files_onefile_picview.html new file mode 100644 index 000000000..f56e409d1 --- /dev/null +++ b/webcit/static/t/section_files_onefile_picview.html @@ -0,0 +1,3 @@ + +fadeimages[]=["download_file/"] + diff --git a/webcit/subst.c b/webcit/subst.c index ac0dd0787..e5adac223 100644 --- a/webcit/subst.c +++ b/webcit/subst.c @@ -59,6 +59,25 @@ typedef struct _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); +typedef struct _SortStruct { + StrBuf *Name; + StrBuf *PrefPrepend; + CompareFunc Forward; + CompareFunc Reverse; + CompareFunc GroupChange; + + long ContextType; +}SortStruct; + +void DestroySortStruct(void *vSort) +{ + SortStruct *Sort = (SortStruct*) vSort; + FreeStrBuf(&Sort->Name); + FreeStrBuf(&Sort->PrefPrepend); + free (Sort); +} + + void RegisterNS(const char *NSName, long len, int nMinArgs, @@ -1450,6 +1469,7 @@ typedef struct _HashIterator { int AdditionalParams; int ContextType; int XPectContextType; + int Flags; RetrieveHashlistFunc GetHash; HashDestructorFunc Destructor; SubTemplFunc DoSubTemplate; @@ -1462,7 +1482,8 @@ void RegisterITERATOR(const char *Name, long len, SubTemplFunc DoSubTempl, HashDestructorFunc Destructor, int ContextType, - int XPectContextType) + int XPectContextType, + int Flags) { HashIterator *It = (HashIterator*)malloc(sizeof(HashIterator)); It->StaticList = StaticList; @@ -1472,6 +1493,7 @@ void RegisterITERATOR(const char *Name, long len, It->Destructor = Destructor; It->ContextType = ContextType; It->XPectContextType = XPectContextType; + It->Flags = Flags; Put(Iterators, Name, len, It, NULL); } @@ -1481,11 +1503,15 @@ void tmpl_iterate_subtmpl(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, vo HashIterator *It; HashList *List; HashPos *it; + SortStruct *SortBy; + void *vSortBy; + int DetectGroupChange = 0; int nMembersUsed; int nMembersCounted = 0; long len; const char *Key; void *vContext; + void *vLastContext; StrBuf *SubBuf; int oddeven = 0; @@ -1558,10 +1584,35 @@ void tmpl_iterate_subtmpl(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, vo else List = It->StaticList; + DetectGroupChange = (It->Flags & IT_FLAG_DETECT_GROUPCHANGE) != 0; + if (DetectGroupChange) { + const StrBuf *BSort; + DetectGroupChange = 0; + if (havebstr("SortBy")) { + BSort = sbstr("SortBy"); + if (GetHash(SortHash, SKEY(BSort), &vSortBy) && + (vSortBy != NULL)) { + SortBy = (SortStruct*)vSortBy; + /** Ok, its us, lets see in which direction we should sort... */ + if (havebstr("SortOrder")) { + int SortOrder; + SortOrder = LBSTR("SortOrder"); + if (SortOrder != 0) + DetectGroupChange = 1; + } + } + } + } nMembersUsed = GetCount(List); SubBuf = NewStrBuf(); it = GetNewHashPos(List, 0); while (GetNextHashPos(List, it, &len, &Key, &vContext)) { + if (DetectGroupChange && nMembersCounted > 0) { + if (SortBy->GroupChange(vContext, vLastContext)) + svputlong("ITERATE:ISGROUPCHANGE", 1); + else + svputlong("ITERATE:ISGROUPCHANGE", 0); + } svprintf(HKEY("ITERATE:ODDEVEN"), WCS_STRING, "%s", (oddeven) ? "odd" : "even"); svprintf(HKEY("ITERATE:KEY"), WCS_STRING, "%s", Key); @@ -1575,6 +1626,7 @@ void tmpl_iterate_subtmpl(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, vo StrBufAppendBuf(Target, SubBuf, 0); FlushStrBuf(SubBuf); oddeven = ~ oddeven; + vLastContext = vContext; } FreeStrBuf(&SubBuf); DeleteHashPos(&it); @@ -1761,27 +1813,12 @@ 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, + CompareFunc GroupChange, long ContextType) { SortStruct *NewSort = (SortStruct*) malloc(sizeof(SortStruct)); @@ -1792,6 +1829,7 @@ void RegisterSortFunc(const char *name, long len, NewSort->PrefPrepend = NULL; NewSort->Forward = Forward; NewSort->Reverse = Reverse; + NewSort->GroupChange = GroupChange; NewSort->ContextType = ContextType; Put(SortHash, name, len, NewSort, DestroySortStruct); } diff --git a/webcit/subst.h b/webcit/subst.h index 58eaa797b..bffa39d20 100644 --- a/webcit/subst.h +++ b/webcit/subst.h @@ -85,6 +85,7 @@ typedef struct _wcsubst { #define CTX_USERLIST 8 #define CTX_MAILSUM 9 #define CTX_MIME_ATACH 10 +#define CTX_FILELIST 11 #define CTX_STRBUF 12 #define CTX_LONGVECTOR 13 @@ -120,8 +121,13 @@ void RegisterITERATOR(const char *Name, long len, /* Our identifier */ SubTemplFunc DoSubTempl, /* call this function on each iteration for svput & friends */ HashDestructorFunc Destructor, /* use this function to shut down the hash; NULL if its a reference */ int ContextType, /* which context do we provide to the subtemplate? */ - int XPectContextType); /* which context do we expct to be called in? */ -#define RegisterIterator(a, b, c, d, e, f, g, h) RegisterITERATOR(a, sizeof(a)-1, b, c, d, e, f, g, h) + int XPectContextType, /* which context do we expct to be called in? */ + int Flags); + +#define IT_NOFLAG 0 +#define IT_FLAG_DETECT_GROUPCHANGE (1<<0) + +#define RegisterIterator(a, b, c, d, e, f, g, h, i) RegisterITERATOR(a, sizeof(a)-1, b, c, d, e, f, g, h, i) void GetTemplateTokenString(WCTemplateToken *Tokens, int N, @@ -160,6 +166,7 @@ void RegisterSortFunc(const char *name, long len, const char *prepend, long preplen, CompareFunc Forward, CompareFunc Reverse, + CompareFunc GroupChange, long ContextType); void dbg_print_longvector(long *LongVector); diff --git a/webcit/useredit.c b/webcit/useredit.c index 312dc65ab..728580dcd 100644 --- a/webcit/useredit.c +++ b/webcit/useredit.c @@ -688,5 +688,5 @@ InitModule_USEREDIT RegisterConditional(HKEY("COND:USERACCESS"), 0, ConditionalUserAccess, CTX_USERLIST); RegisterConditional(HKEY("COND:USERLIST:FLAG:USE_INTERNET"), 0, ConditionalFlagINetEmail, CTX_USERLIST); - RegisterIterator("USERLIST", 0, NULL, iterate_load_userlist, NULL, DeleteHash, CTX_USERLIST, CTX_NONE); + RegisterIterator("USERLIST", 0, NULL, iterate_load_userlist, NULL, DeleteHash, CTX_USERLIST, CTX_NONE, IT_NOFLAG); } diff --git a/webcit/who.c b/webcit/who.c index b4a977197..2edf9c64a 100644 --- a/webcit/who.c +++ b/webcit/who.c @@ -319,7 +319,7 @@ InitModule_WHO WebcitAddUrlHandler(HKEY("terminate_session"), _terminate_session, 0); WebcitAddUrlHandler(HKEY("edit_me"), edit_me, 0); - RegisterIterator("WHOLIST", 0, NULL, GetWholistHash, NULL, DeleteWholistHash, CTX_WHO, CTX_NONE); + RegisterIterator("WHOLIST", 0, NULL, GetWholistHash, NULL, DeleteWholistHash, CTX_WHO, CTX_NONE, IT_NOFLAG); RegisterNamespace("WHO:NAME", 0, 1, tmplput_who_username, CTX_WHO); RegisterNamespace("WHO:ROOM", 0, 1, tmplput_who_room, CTX_WHO); -- 2.30.2