diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 16:49:23 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 16:49:23 +0000 |
commit | cf123a1c2e624e7b4908a03870ca0a48420a3c43 (patch) | |
tree | 3f41d5e5a19a9de4f3ff8cf5ba363f8bc7b0f2fa /toc.c |
Initial revisionXORG-STABLE
Diffstat (limited to 'toc.c')
-rw-r--r-- | toc.c | 1220 |
1 files changed, 1220 insertions, 0 deletions
@@ -0,0 +1,1220 @@ +/* $XConsortium: toc.c,v 2.59 95/01/09 16:52:53 swick Exp $ + * $XFree86: xc/programs/xmh/toc.c,v 3.5 2002/04/05 21:06:29 dickey Exp $ + * + * + * COPYRIGHT 1987 + * DIGITAL EQUIPMENT CORPORATION + * MAYNARD, MASSACHUSETTS + * ALL RIGHTS RESERVED. + * + * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND + * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION. + * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR + * ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. + * + * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT + * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN + * ADDITION TO THAT SET FORTH ABOVE. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Digital Equipment Corporation not be + * used in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. + */ + +/* toc.c -- handle things in the toc widget. */ + +#include "xmh.h" +#include "tocintrnl.h" +#include "toc.h" +#include "tocutil.h" +#include "actions.h" + +#include <sys/stat.h> + +static int IsDir(char *name) +{ + char str[500]; + struct stat buf; + if (*name == '.') + return FALSE; + (void) sprintf(str, "%s/%s", app_resources.mail_path, name); + if (stat(str, &buf) /* failed */) return False; +#ifdef S_ISDIR + return S_ISDIR(buf.st_mode); +#else + return (buf.st_mode & S_IFMT) == S_IFDIR; +#endif +} + + +static void MakeSureFolderExists( + char ***namelistptr, + int *numfoldersptr, + char *name) +{ + int i; + char str[200]; + for (i=0 ; i<*numfoldersptr ; i++) + if (strcmp((*namelistptr)[i], name) == 0) return; + (void) sprintf(str, "%s/%s", app_resources.mail_path, name); + (void) mkdir(str, 0700); + *numfoldersptr = ScanDir(app_resources.mail_path, namelistptr, IsDir); + for (i=0 ; i<*numfoldersptr ; i++) + if (strcmp((*namelistptr)[i], name) == 0) return; + Punt("Can't create new mail folder!"); +} + + +static void MakeSureSubfolderExists( + char *** namelistptr, + int * numfoldersptr, + char * name) +{ + char folder[300]; + char subfolder_path[300]; + char *subfolder; + struct stat buf; + + /* Make sure that the parent folder exists */ + + subfolder = strchr( strcpy(folder, name), '/'); + *subfolder = '\0'; + subfolder++; + MakeSureFolderExists(namelistptr, numfoldersptr, folder); + + /* The parent folder exists. Make sure the subfolder exists. */ + + (void) sprintf(subfolder_path, "%s/%s", app_resources.mail_path, name); + if (stat(subfolder_path, &buf) /* failed */) { + (void) mkdir(subfolder_path, 0700); + if (stat(subfolder_path, &buf) /* failed */) + Punt("Can't create new xmh subfolder!"); + } +#ifdef S_ISDIR + if (!S_ISDIR(buf.st_mode)) +#else + if ((buf.st_mode & S_IFMT) != S_IFDIR) +#endif + Punt("Can't create new xmh subfolder!"); +} + +int TocFolderExists(Toc toc) +{ + struct stat buf; + if (! toc->path) { + char str[500]; + (void) sprintf(str, "%s/%s", app_resources.mail_path, toc->foldername); + toc->path = XtNewString(str); + } + return ((stat(toc->path, &buf) == 0) && +#ifdef S_ISDIR + (S_ISDIR(buf.st_mode))); +#else + ((buf.st_mode & S_IFMT) == S_IFDIR)); +#endif +} + +static void LoadCheckFiles(void) +{ + FILE *fid; + char str[1024]; + + (void) sprintf(str, "%s/.xmhcheck", homeDir); + fid = myfopen(str, "r"); + if (fid) { + int i; + char *ptr, *ptr2; + + while ((ptr = ReadLine(fid))) { + while (*ptr == ' ' || *ptr == '\t') ptr++; + ptr2 = ptr; + while (*ptr2 && *ptr2 != ' ' && *ptr2 != '\t') ptr2++; + if (*ptr2 == 0) continue; + *ptr2++ = 0; + while (*ptr2 == ' ' || *ptr2 == '\t') ptr2++; + if (*ptr2 == 0) continue; + for (i=0 ; i<numFolders ; i++) { + if (strcmp(ptr, folderList[i]->foldername) == 0) { + folderList[i]->incfile = XtNewString(ptr2); + break; + } + } + } + myfclose(fid); + } else if ( app_resources.initial_inc_file && + *app_resources.initial_inc_file) + InitialFolder->incfile = app_resources.initial_inc_file; +} + + +/* PUBLIC ROUTINES */ + + +/* Read in the list of folders. */ + +void TocInit(void) +{ + Toc toc; + char **namelist; + int i; + numFolders = ScanDir(app_resources.mail_path, &namelist, IsDir); + if (numFolders < 0) { + (void) mkdir(app_resources.mail_path, 0700); + numFolders = ScanDir(app_resources.mail_path, &namelist, IsDir); + if (numFolders < 0) + Punt("Can't create or read mail directory!"); + } + if (IsSubfolder(app_resources.initial_folder_name)) + MakeSureSubfolderExists(&namelist, &numFolders, + app_resources.initial_folder_name); + else + MakeSureFolderExists(&namelist, &numFolders, + app_resources.initial_folder_name); + + if (IsSubfolder(app_resources.drafts_folder_name)) + MakeSureSubfolderExists(&namelist, &numFolders, + app_resources.drafts_folder_name); + else + MakeSureFolderExists(&namelist, &numFolders, + app_resources.drafts_folder_name); + folderList = (Toc *) XtMalloc((Cardinal)numFolders * sizeof(Toc)); + for (i=0 ; i<numFolders ; i++) { + toc = folderList[i] = TUMalloc(); + toc->foldername = XtNewString(namelist[i]); + free((char *)namelist[i]); + } + if (! (InitialFolder = TocGetNamed(app_resources.initial_folder_name))) + InitialFolder = TocCreate(app_resources.initial_folder_name); + + if (! (DraftsFolder = TocGetNamed(app_resources.drafts_folder_name))) + DraftsFolder = TocCreate(app_resources.drafts_folder_name); + free((char *)namelist); + LoadCheckFiles(); +} + + + +/* Create a toc and add a folder to the folderList. */ + +Toc TocCreate(char *foldername) +{ + Toc toc = TUMalloc(); + + toc->foldername = XtNewString(foldername); + folderList = (Toc *) XtRealloc((char *) folderList, + (unsigned) ++numFolders * sizeof(Toc)); + folderList[numFolders - 1] = toc; + return toc; +} + + +/* Create a new folder with the given name. */ + +Toc TocCreateFolder(char *foldername) +{ + Toc toc; + char str[500]; + if (TocGetNamed(foldername)) return NULL; + (void) sprintf(str, "%s/%s", app_resources.mail_path, foldername); + if (mkdir(str, 0700) < 0) return NULL; + toc = TocCreate(foldername); + return toc; +} + +int TocHasMail(Toc toc) +{ + return toc->mailpending; +} + +static int CheckForNewMail(Toc toc) +{ + if (toc->incfile) + return (GetFileLength(toc->incfile) > 0); + else if (toc == InitialFolder) { + char **argv; + char *result; + int hasmail; + + argv = MakeArgv(4); + argv[0] = "msgchk"; + argv[1] = "-nonotify"; + argv[2] = "nomail"; + argv[3] = "-nodate"; + result = DoCommandToString(argv); + hasmail = (*result != '\0'); + XtFree(result); + XtFree((char*)argv); + return hasmail; + } + return False; +} + +/*ARGSUSED*/ +void TocCheckForNewMail( + Boolean update) /* if True, actually make the check */ +{ + Toc toc; + Scrn scrn; + int i, j, hasmail; + Boolean mail_waiting = False; + + if (update) { + for (i=0 ; i<numFolders ; i++) { + toc = folderList[i]; + if (TocCanIncorporate(toc)) { + toc->mailpending = hasmail = CheckForNewMail(toc); + if (hasmail) mail_waiting = True; + for (j=0 ; j<numScrns ; j++) { + scrn = scrnList[j]; + if (scrn->kind == STtocAndView) + /* give visual indication of new mail waiting */ + BBoxMailFlag(scrn->folderbuttons, TocName(toc), + hasmail); + } + } + } + } else { + for (i=0; i < numFolders; i++) { + toc = folderList[i]; + if (toc->mailpending) { + mail_waiting = True; + break; + } + } + } + + if (app_resources.mail_waiting_flag) { + Arg args[1]; + static Boolean icon_state = -1; + + if (icon_state != mail_waiting) { + icon_state = mail_waiting; + for (i=0; i < numScrns; i++) { + scrn = scrnList[i]; + if (scrn->kind == STtocAndView) { + XtSetArg(args[0], XtNiconPixmap, + (mail_waiting ? app_resources.new_mail_icon + : app_resources.no_mail_icon)); + XtSetValues(scrn->parent, args, (Cardinal)1); + } + } + } + } +} + +/* Intended to support mutual exclusion on deleting folders, so that you + * cannot have two confirm popups at the same time on the same folder. + * + * You can have confirm popups on different folders simultaneously. + * However, I did not protect the user from popping up a delete confirm + * popup on folder A, then popping up a delete confirm popup on folder + * A/subA, then deleting A, then deleting A/subA -- which of course is + * already gone, and will cause xmh to Punt. + * + * TocClearDeletePending is a callback from the No confirmation button + * of the confirm popup. + */ + +Boolean TocTestAndSetDeletePending(Toc toc) +{ + Boolean flag; + + flag = toc->delete_pending; + toc->delete_pending = True; + return flag; +} + +void TocClearDeletePending(Toc toc) +{ + toc->delete_pending = False; +} + + +/* Recursively delete an entire directory. Nasty. */ + +static void NukeDirectory(char *path) +{ + struct stat buf; + +#ifdef S_IFLNK + /* POSIX.1 does not discuss symbolic links. */ + if (lstat(path, &buf) /* failed */) + return; + if ((buf.st_mode & S_IFMT) == S_IFLNK) { + (void) unlink(path); + return; + } +#endif + if (stat(path, &buf) /* failed */) + return; + if (buf.st_mode & S_IWRITE) { + char **argv = MakeArgv(3); + argv[0] = "/bin/rm"; + argv[1] = "-rf"; + argv[2] = path; + (void) DoCommand(argv, (char*)NULL, (char*)NULL); + XtFree((char*)argv); + } +} + + +/* Destroy the given folder. */ + +void TocDeleteFolder(Toc toc) +{ + Toc toc2; + int i, j, w; + if (toc == NULL) return; + TUGetFullFolderInfo(toc); + + w = -1; + for (i=0 ; i<numFolders ; i++) { + toc2 = folderList[i]; + if (toc2 == toc) + w = i; + else if (toc2->validity == valid) + for (j=0 ; j<toc2->nummsgs ; j++) + if (toc2->msgs[j]->desttoc == toc) + MsgSetFate(toc2->msgs[j], Fignore, (Toc) NULL); + } + if (w < 0) Punt("Couldn't find it in TocDeleteFolder!"); + NukeDirectory(toc->path); + if (toc->validity == valid) { + for (i=0 ; i<toc->nummsgs ; i++) { + MsgSetScrnForce(toc->msgs[i], (Scrn) NULL); + MsgFree(toc->msgs[i]); + } + XtFree((char *) toc->msgs); + } + XtFree((char *)toc); + numFolders--; + for (i=w ; i<numFolders ; i++) folderList[i] = folderList[i+1]; +} + + +/* + * Display the given toc in the given scrn. If scrn is NULL, then remove the + * toc from all scrns displaying it. + */ + +void TocSetScrn(Toc toc, Scrn scrn) +{ + Cardinal i; + + if (toc == NULL && scrn == NULL) return; + if (scrn == NULL) { + for (i=0 ; i<toc->num_scrns ; i++) + TocSetScrn((Toc) NULL, toc->scrn[i]); + return; + } + if (scrn->toc == toc) return; + if (scrn->toc != NULL) { + for (i=0 ; i<scrn->toc->num_scrns ; i++) + if (scrn->toc->scrn[i] == scrn) break; + if (i >= scrn->toc->num_scrns) + Punt("Couldn't find scrn in TocSetScrn!"); + scrn->toc->scrn[i] = scrn->toc->scrn[--scrn->toc->num_scrns]; + } + scrn->toc = toc; + if (toc == NULL) { + TUResetTocLabel(scrn); + TURedisplayToc(scrn); + StoreWindowName(scrn, progName); + } else { + toc->num_scrns++; + toc->scrn = (Scrn *) XtRealloc((char *) toc->scrn, + (unsigned)toc->num_scrns*sizeof(Scrn)); + toc->scrn[toc->num_scrns - 1] = scrn; + TUEnsureScanIsValidAndOpen(toc, True); + TUResetTocLabel(scrn); + if (app_resources.prefix_wm_and_icon_name) { + char wm_name[64]; + int length = strlen(progName); + (void) strncpy(wm_name, progName, length); + (void) strncpy(wm_name + length , ": ", 2); + (void) strcpy(wm_name + length + 2, toc->foldername); + StoreWindowName(scrn, wm_name); + } + else + StoreWindowName(scrn, toc->foldername); + TURedisplayToc(scrn); + SetCurrentFolderName(scrn, toc->foldername); + } + EnableProperButtons(scrn); +} + + + +/* Remove the given message from the toc. Doesn't actually touch the file. + Also note that it does not free the storage for the msg. */ + +void TocRemoveMsg(Toc toc, Msg msg) +{ + Msg newcurmsg; + MsgList mlist; + int i; + if (toc->validity == unknown) + TUGetFullFolderInfo(toc); + if (toc->validity != valid) + return; + newcurmsg = TocMsgAfter(toc, msg); + if (newcurmsg) newcurmsg->changed = TRUE; + newcurmsg = toc->curmsg; + if (msg == toc->curmsg) { + newcurmsg = TocMsgAfter(toc, msg); + if (newcurmsg == NULL) newcurmsg = TocMsgBefore(toc, msg); + toc->curmsg = NULL; + } + toc->length -= msg->length; + if (msg->visible) toc->lastPos -= msg->length; + for(i = TUGetMsgPosition(toc, msg), toc->nummsgs--; i<toc->nummsgs ; i++) { + toc->msgs[i] = toc->msgs[i+1]; + if (msg->visible) toc->msgs[i]->position -= msg->length; + } + for (i=0 ; i<toc->numsequences ; i++) { + mlist = toc->seqlist[i]->mlist; + if (mlist) DeleteMsgFromMsgList(mlist, msg); + } + + if (msg->visible && toc->num_scrns > 0 && !toc->needsrepaint) + TSourceInvalid(toc, msg->position, -msg->length); + TocSetCurMsg(toc, newcurmsg); + TUSaveTocFile(toc); +} + + + +void TocRecheckValidity(Toc toc) +{ + Cardinal i; + + if (toc && toc->validity == valid && TUScanFileOutOfDate(toc)) { + if (app_resources.block_events_on_busy) ShowBusyCursor(); + + TUScanFileForToc(toc); + if (toc->source) + TULoadTocFile(toc); + for (i=0 ; i<toc->num_scrns ; i++) + TURedisplayToc(toc->scrn[i]); + + if (app_resources.block_events_on_busy) UnshowBusyCursor(); + } +} + + +/* Set the current message. */ + +void TocSetCurMsg(Toc toc, Msg msg) +{ + Msg msg2; + Cardinal i; + + if (toc->validity != valid) return; + if (msg != toc->curmsg) { + msg2 = toc->curmsg; + toc->curmsg = msg; + if (msg2) + MsgSetFate(msg2, msg2->fate, msg2->desttoc); + } + if (msg) { + MsgSetFate(msg, msg->fate, msg->desttoc); + if (toc->num_scrns) { + if (toc->stopupdate) + toc->needsrepaint = TRUE; + else { + for (i=0 ; i<toc->num_scrns ; i++) + XawTextSetInsertionPoint(toc->scrn[i]->tocwidget, + msg->position); + } + } + } +} + + +/* Return the current message. */ + +Msg TocGetCurMsg(Toc toc) +{ + return toc->curmsg; +} + + + + +/* Return the message after the given one. (If none, return NULL.) */ + +Msg TocMsgAfter(Toc toc, Msg msg) +{ + int i; + i = TUGetMsgPosition(toc, msg); + do { + i++; + if (i >= toc->nummsgs) + return NULL; + } while (!(toc->msgs[i]->visible)); + return toc->msgs[i]; +} + + + +/* Return the message before the given one. (If none, return NULL.) */ + +Msg TocMsgBefore(Toc toc, Msg msg) +{ + int i; + i = TUGetMsgPosition(toc, msg); + do { + i--; + if (i < 0) + return NULL; + } while (!(toc->msgs[i]->visible)); + return toc->msgs[i]; +} + + + +/* The caller KNOWS the toc's information is out of date; rescan it. */ + +void TocForceRescan(Toc toc) +{ + register Cardinal i; + + if (toc->num_scrns) { + toc->viewedseq = toc->seqlist[0]; + for (i=0 ; i<toc->num_scrns ; i++) + TUResetTocLabel(toc->scrn[i]); + TUScanFileForToc(toc); + TULoadTocFile(toc); + for (i=0 ; i<toc->num_scrns ; i++) + TURedisplayToc(toc->scrn[i]); + } else { + TUGetFullFolderInfo(toc); + (void) unlink(toc->scanfile); + toc->validity = invalid; + } +} + + + +/* The caller has just changed a sequence list. Reread them from mh. */ + +void TocReloadSeqLists(Toc toc) +{ + Cardinal i; + + TocSetCacheValid(toc); + TULoadSeqLists(toc); + TURefigureWhatsVisible(toc); + for (i=0 ; i<toc->num_scrns ; i++) { + TUResetTocLabel(toc->scrn[i]); + EnableProperButtons(toc->scrn[i]); + } +} + + +/*ARGSUSED*/ +void XmhReloadSeqLists( + Widget w, + XEvent *event, + String *params, + Cardinal *num_params) +{ + Scrn scrn = ScrnFromWidget(w); + TocReloadSeqLists(scrn->toc); + TUCheckSequenceMenu(scrn->toc); +} + + + +/* Return TRUE if the toc has an interesting sequence. */ + +int TocHasSequences(Toc toc) +{ + return toc && toc->numsequences > 1; +} + + +/* Change which sequence is being viewed. */ + +void TocChangeViewedSeq(Toc toc, Sequence seq) +{ + if (seq == NULL) seq = toc->viewedseq; + toc->viewedseq = seq; + toc->force_reset = True; /* %%% force Text source to be reset */ + TURefigureWhatsVisible(toc); +} + + +/* Return the sequence with the given name in the given toc. */ + +Sequence TocGetSeqNamed(Toc toc, char *name) +{ + register int i; + if (name == NULL) + return (Sequence) NULL; + + for (i=0 ; i<toc->numsequences ; i++) + if (strcmp(toc->seqlist[i]->name, name) == 0) + return toc->seqlist[i]; + return (Sequence) NULL; +} + + +/* Return the sequence currently being viewed in the toc. */ + +Sequence TocViewedSequence(Toc toc) +{ + return toc->viewedseq; +} + + +/* Set the selected sequence in the toc */ + +void TocSetSelectedSequence( + Toc toc, + Sequence sequence) +{ + if (toc) + toc->selectseq = sequence; +} + + +/* Return the sequence currently selected */ + +Sequence TocSelectedSequence(Toc toc) +{ + if (toc) return (toc->selectseq); + else return (Sequence) NULL; +} + + +/* Return the list of messages currently selected. */ + +#define SrcScan XawTextSourceScan + +MsgList TocCurMsgList(Toc toc) +{ + MsgList result; + XawTextPosition pos1, pos2; + + if (toc->num_scrns == 0) return NULL; + result = MakeNullMsgList(); + XawTextGetSelectionPos( toc->scrn[0]->tocwidget, &pos1, &pos2); /* %%% */ + if (pos1 < pos2) { + pos1 = SrcScan(toc->source, pos1, XawstEOL, XawsdLeft, 1, FALSE); + pos2 = SrcScan(toc->source, pos2, XawstPositions, XawsdLeft, 1, TRUE); + pos2 = SrcScan(toc->source, pos2, XawstEOL, XawsdRight, 1, FALSE); + while (pos1 < pos2) { + AppendMsgList(result, MsgFromPosition(toc, pos1, XawsdRight)); + pos1 = SrcScan(toc->source, pos1, XawstEOL, XawsdRight, 1, TRUE); + } + } + return result; +} + + + +/* Unset the current selection. */ + +void TocUnsetSelection(Toc toc) +{ + if (toc->source) + XawTextUnsetSelection(toc->scrn[0]->tocwidget); +} + + + +/* Create a brand new, blank message. */ + +Msg TocMakeNewMsg(Toc toc) +{ + Msg msg; + static int looping = False; + TUEnsureScanIsValidAndOpen(toc, False); + msg = TUAppendToc(toc, "#### empty\n"); + if (FileExists(MsgFileName(msg))) { + if (looping++) Punt( "Cannot correct scan file" ); + DEBUG2("**** FOLDER %s WAS INVALID; msg %d already existed!\n", + toc->foldername, msg->msgid); + TocForceRescan(toc); + return TocMakeNewMsg(toc); /* Try again. Using recursion here is ugly, + but what the hack ... */ + } + CopyFileAndCheck("/dev/null", MsgFileName(msg)); + looping = False; + return msg; +} + + +/* Set things to not update cache or display until further notice. */ + +void TocStopUpdate(Toc toc) +{ + Cardinal i; + + for (i=0 ; i<toc->num_scrns ; i++) + XawTextDisableRedisplay(toc->scrn[i]->tocwidget); + toc->stopupdate++; +} + + +/* Start updating again, and do whatever updating has been queued. */ + +void TocStartUpdate(Toc toc) +{ + Cardinal i; + + if (toc->stopupdate && --(toc->stopupdate) == 0) { + for (i=0 ; i<toc->num_scrns ; i++) { + if (toc->needsrepaint) + TURedisplayToc(toc->scrn[i]); + if (toc->needslabelupdate) + TUResetTocLabel(toc->scrn[i]); + } + if (toc->needscachesave) + TUSaveTocFile(toc); + } + for (i=0 ; i<toc->num_scrns ; i++) + XawTextEnableRedisplay(toc->scrn[i]->tocwidget); +} + + + +/* Something has happened that could later convince us that our cache is out + of date. Make this not happen; our cache really *is* up-to-date. */ + +void TocSetCacheValid(Toc toc) +{ + TUSaveTocFile(toc); +} + + +/* Return the full folder pathname of the given toc, prefixed w/'+' */ + +char *TocMakeFolderName(Toc toc) +{ + char* name = XtMalloc((Cardinal) (strlen(toc->path) + 2) ); + (void)sprintf( name, "+%s", toc->path ); + return name; +} + +char *TocName(Toc toc) +{ + return toc->foldername; +} + + + +/* Given a foldername, return the corresponding toc. */ + +Toc TocGetNamed(char *name) +{ + int i; + for (i=0; i<numFolders ; i++) + if (strcmp(folderList[i]->foldername, name) == 0) return folderList[i]; + return NULL; +} + + +Boolean TocHasChanges(Toc toc) +{ + int i; + for (i=0 ; i<toc->nummsgs ; i++) + if (toc->msgs[i]->fate != Fignore) return True; + + return False; +} + + + +/* Throw out all changes to this toc, and close all views of msgs in it. + Requires confirmation by the user. */ + +/*ARGSUSED*/ +static void TocCataclysmOkay( + Widget widget, /* unused */ + XtPointer client_data, + XtPointer call_data) /* unused */ +{ + Toc toc = (Toc) client_data; + register int i; + + for (i=0; i < toc->nummsgs; i++) + MsgSetFate(toc->msgs[i], Fignore, (Toc)NULL); + +/* Doesn't make sense to have this MsgSetScrn for loop here. dmc. %%% */ + for (i=0; i < toc->nummsgs; i++) + MsgSetScrn(toc->msgs[i], (Scrn) NULL, (XtCallbackList) NULL, + (XtCallbackList) NULL); +} + +int TocConfirmCataclysm( + Toc toc, + XtCallbackList confirms, + XtCallbackList cancels) +{ + register int i; + + static XtCallbackRec yes_callbacks[] = { + {TocCataclysmOkay, (XtPointer) NULL}, + {(XtCallbackProc) NULL, (XtPointer) NULL}, + {(XtCallbackProc) NULL, (XtPointer) NULL} + }; + + if (! toc) + return 0; + + if (TocHasChanges(toc)) { + char str[300]; + Widget tocwidget; + + (void)sprintf(str,"Are you sure you want to remove all changes to %s?", + toc->foldername); + yes_callbacks[0].closure = (XtPointer) toc; + yes_callbacks[1].callback = confirms[0].callback; + yes_callbacks[1].closure = confirms[0].closure; + + tocwidget = NULL; + for (i=0; i < toc->num_scrns; i++) + if (toc->scrn[i]->mapped) { + tocwidget = toc->scrn[i]->tocwidget; + break; + } + + PopupConfirm(tocwidget, str, yes_callbacks, cancels); + return NEEDS_CONFIRMATION; + } + else { +/* Doesn't make sense to have this MsgSetFate for loop here. dmc. %%% */ + for (i=0 ; i<toc->nummsgs ; i++) + MsgSetFate(toc->msgs[i], Fignore, (Toc)NULL); + + for (i=0 ; i<toc->nummsgs ; i++) + if (MsgSetScrn(toc->msgs[i], (Scrn) NULL, confirms, cancels)) + return NEEDS_CONFIRMATION; + return 0; + } +} + + +/* Commit all the changes in this toc; all messages will meet their 'fate'. */ + +/*ARGSUSED*/ +void TocCommitChanges( + Widget widget, /* unused */ + XtPointer client_data, + XtPointer call_data) /* unused */ +{ + Toc toc = (Toc) client_data; + Msg msg; + int i, cur = 0; + char str[100], **argv = NULL; + FateType curfate, fate; + Toc desttoc; + Toc curdesttoc = NULL; + XtCallbackRec confirms[2]; + + confirms[0].callback = TocCommitChanges; + confirms[0].closure = (XtPointer) toc; + confirms[1].callback = (XtCallbackProc) NULL; + confirms[1].closure = (XtPointer) NULL; + + if (toc == NULL) return; + for (i=0 ; i<toc->nummsgs ; i++) { + msg = toc->msgs[i]; + fate = MsgGetFate(msg, (Toc *)NULL); + if (fate != Fignore && fate != Fcopy) + if (MsgSetScrn(msg, (Scrn) NULL, confirms, (XtCallbackList) NULL) + == NEEDS_CONFIRMATION) + return; + } + XFlush(XtDisplay(toc->scrn[0]->parent)); + for (i=0 ; i<numFolders ; i++) + TocStopUpdate(folderList[i]); + toc->haschanged = TRUE; + if (app_resources.block_events_on_busy) ShowBusyCursor(); + + do { + curfate = Fignore; + i = 0; + while (i < toc->nummsgs) { + msg = toc->msgs[i]; + fate = MsgGetFate(msg, &desttoc); + if (curfate == Fignore && fate != Fignore) { + curfate = fate; + argv = MakeArgv(2); + switch (curfate) { + case Fdelete: + argv[0] = XtNewString("rmm"); + argv[1] = TocMakeFolderName(toc); + cur = 2; + curdesttoc = NULL; + break; + case Fmove: + case Fcopy: + argv[0] = XtNewString("refile"); + cur = 1; + curdesttoc = desttoc; + break; + default: + break; + } + } + if (curfate != Fignore && + curfate == fate && desttoc == curdesttoc) { + argv = ResizeArgv(argv, cur + 1); + (void) sprintf(str, "%d", MsgGetId(msg)); + argv[cur++] = XtNewString(str); + MsgSetFate(msg, Fignore, (Toc)NULL); + if (curdesttoc) { + (void) TUAppendToc(curdesttoc, MsgGetScanLine(msg)); + curdesttoc->haschanged = TRUE; + } + if (curfate != Fcopy) { + TocRemoveMsg(toc, msg); + MsgFree(msg); + i--; + } + if (cur > 40) + break; /* Do only 40 at a time, just to be safe. */ + } + i++; + } + if (curfate != Fignore) { + switch (curfate) { + case Fmove: + case Fcopy: + argv = ResizeArgv(argv, cur + 4); + argv[cur++] = XtNewString(curfate == Fmove ? "-nolink" + : "-link"); + argv[cur++] = XtNewString("-src"); + argv[cur++] = TocMakeFolderName(toc); + argv[cur++] = TocMakeFolderName(curdesttoc); + break; + default: + break; + } + if (app_resources.debug) { + for (i = 0; i < cur; i++) + (void) fprintf(stderr, "%s ", argv[i]); + (void) fprintf(stderr, "\n"); + (void) fflush(stderr); + } + DoCommand(argv, (char *) NULL, (char *) NULL); + for (i = 0; argv[i]; i++) + XtFree((char *) argv[i]); + XtFree((char *) argv); + } + } while (curfate != Fignore); + for (i=0 ; i<numFolders ; i++) { + if (folderList[i]->haschanged) { + TocReloadSeqLists(folderList[i]); + folderList[i]->haschanged = FALSE; + } + TocStartUpdate(folderList[i]); + } + + if (app_resources.block_events_on_busy) UnshowBusyCursor(); +} + + + +/* Return whether the given toc can incorporate mail. */ + +int TocCanIncorporate(Toc toc) +{ + return (toc && (toc == InitialFolder || toc->incfile)); +} + + +/* Incorporate new messages into the given toc. */ + +int TocIncorporate(Toc toc) +{ + char **argv; + char str[100], *file, *ptr; + Msg msg, firstmessage = NULL; + FILEPTR fid; + + argv = MakeArgv(toc->incfile ? 7 : 4); + argv[0] = "inc"; + argv[1] = TocMakeFolderName(toc); + argv[2] = "-width"; + (void) sprintf(str, "%d", app_resources.toc_width); + argv[3] = str; + if (toc->incfile) { + argv[4] = "-file"; + argv[5] = toc->incfile; + argv[6] = "-truncate"; + } + if (app_resources.block_events_on_busy) ShowBusyCursor(); + + file = DoCommandToFile(argv); + XtFree(argv[1]); + XtFree((char *)argv); + TUGetFullFolderInfo(toc); + if (toc->validity == valid) { + fid = FOpenAndCheck(file, "r"); + TocStopUpdate(toc); + while ((ptr = ReadLineWithCR(fid))) { + if (atoi(ptr) > 0) { + msg = TUAppendToc(toc, ptr); + if (firstmessage == NULL) firstmessage = msg; + } + } + if (firstmessage && firstmessage->visible) { + TocSetCurMsg(toc, firstmessage); + } + TocStartUpdate(toc); + myfclose(fid); + } + DeleteFileAndCheck(file); + + if (app_resources.block_events_on_busy) UnshowBusyCursor(); + + toc->mailpending = False; + return (firstmessage != NULL); +} + + +/* The given message has changed. Rescan it and change the scanfile. */ + +void TocMsgChanged(Toc toc, Msg msg) +{ + char **argv, str[100], str2[10], *ptr; + int length, delta; + int i; + FateType fate; + Toc desttoc; + + if (toc->validity != valid) return; + fate = MsgGetFate(msg, &desttoc); + MsgSetFate(msg, Fignore, (Toc) NULL); + argv = MakeArgv(6); + argv[0] = "scan"; + argv[1] = TocMakeFolderName(toc); + (void) sprintf(str, "%d", msg->msgid); + argv[2] = str; + argv[3] = "-width"; + (void) sprintf(str2, "%d", app_resources.toc_width); + argv[4] = str2; + argv[5] = "-noheader"; + ptr = DoCommandToString(argv); + XtFree(argv[1]); + XtFree((char *) argv); + if (strcmp(ptr, msg->buf) != 0) { + length = strlen(ptr); + delta = length - msg->length; + XtFree(msg->buf); + msg->buf = ptr; + msg->length = length; + toc->length += delta; + if (msg->visible) { + if (delta != 0) { + for (i=TUGetMsgPosition(toc, msg)+1; i<toc->nummsgs ; i++) + toc->msgs[i]->position += delta; + toc->lastPos += delta; + } + for (i=0 ; i<toc->num_scrns ; i++) + TURedisplayToc(toc->scrn[i]); + } + MsgSetFate(msg, fate, desttoc); + TUSaveTocFile(toc); + } else XtFree(ptr); +} + + + +Msg TocMsgFromId(Toc toc, int msgid) +{ + int h, l, m; + l = 0; + h = toc->nummsgs - 1; + if (h < 0) { + if (app_resources.debug) { + char str[100]; + (void)sprintf(str, "Toc is empty! folder=%s\n", toc->foldername); + DEBUG( str ) + } + return NULL; + } + while (l < h - 1) { + m = (l + h) / 2; + if (toc->msgs[m]->msgid > msgid) + h = m; + else + l = m; + } + if (toc->msgs[l]->msgid == msgid) return toc->msgs[l]; + if (toc->msgs[h]->msgid == msgid) return toc->msgs[h]; + if (app_resources.debug) { + char str[100]; + (void) sprintf(str, + "TocMsgFromId search failed! hi=%d, lo=%d, msgid=%d\n", + h, l, msgid); + DEBUG( str ) + } + return NULL; +} + +/* Sequence names are put on a stack which is specific to the folder. + * Sequence names are very volatile, so we make our own copies of the strings. + */ + +/*ARGSUSED*/ +void XmhPushSequence( + Widget w, + XEvent *event, + String *params, + Cardinal *count) +{ + Scrn scrn = ScrnFromWidget(w); + Toc toc; + Cardinal i; + + if (! (toc = scrn->toc)) return; + + if (*count == 0) { + if (toc->selectseq) + Push(&toc->sequence_stack, XtNewString(toc->selectseq->name)); + } + else + for (i=0; i < *count; i++) + Push(&toc->sequence_stack, XtNewString(params[i])); +} + + +/*ARGSUSED*/ +void XmhPopSequence( + Widget w, /* any widget on the screen of interest */ + XEvent *event, + String *params, + Cardinal *count) +{ + Scrn scrn = ScrnFromWidget(w); + char *seqname; + Widget sequenceMenu, selected, original; + Button button; + Sequence sequence; + + if ((seqname = Pop(&scrn->toc->sequence_stack)) != NULL) { + + button = BBoxFindButtonNamed(scrn->mainbuttons, + MenuBoxButtons[XMH_SEQUENCE].button_name); + sequenceMenu = BBoxMenuOfButton(button); + + if ((selected = XawSimpleMenuGetActiveEntry(sequenceMenu))) + ToggleMenuItem(selected, False); + + if ((original = XtNameToWidget(sequenceMenu, seqname))) { + ToggleMenuItem(original, True); + sequence = TocGetSeqNamed(scrn->toc, seqname); + TocSetSelectedSequence(scrn->toc, sequence); + } + XtFree(seqname); + } +} |