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 /tocutil.c |
Initial revisionXORG-STABLE
Diffstat (limited to 'tocutil.c')
-rw-r--r-- | tocutil.c | 645 |
1 files changed, 645 insertions, 0 deletions
diff --git a/tocutil.c b/tocutil.c new file mode 100644 index 0000000..72be172 --- /dev/null +++ b/tocutil.c @@ -0,0 +1,645 @@ +/* + * $XConsortium: tocutil.c,v 2.60 95/01/09 16:52:53 swick Exp $ + * $XFree86: xc/programs/xmh/tocutil.c,v 3.4 2002/04/05 21:06:29 dickey Exp $ + * + * + * COPYRIGHT 1987, 1989 + * 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. + */ + +/* tocutil.c -- internal routines for toc stuff. */ + +#include "xmh.h" +#include "toc.h" +#include "tocutil.h" +#include "tocintrnl.h" + +#ifdef X_NOT_POSIX +extern long lseek(); +#endif + +Toc TUMalloc(void) +{ + Toc toc; + toc = XtNew(TocRec); + bzero((char *)toc, (int) sizeof(TocRec)); + toc->msgs = (Msg *) NULL; + toc->seqlist = (Sequence *) NULL; + toc->validity = unknown; + return toc; +} + + +/* Returns TRUE if the scan file for the given toc is out of date. */ + +int TUScanFileOutOfDate(Toc toc) +{ + return LastModifyDate(toc->path) > toc->lastreaddate; +} + + +/* Make sure the sequence menu entries correspond exactly to the sequences + * for this toc. + */ + +void TUCheckSequenceMenu(Toc toc) +{ + Scrn scrn; + register int i, n; + Arg query_args[2]; + char *name; + Cardinal j; + int numChildren; + Widget menu, item; + Button button; + WidgetList children; + + static XtCallbackRec callbacks[] = { + { DoSelectSequence, (XtPointer) NULL}, + { (XtCallbackProc) NULL, (XtPointer) NULL}, + }; + static Arg args[] = { + { XtNcallback, (XtArgVal) callbacks}, + { XtNleftMargin, (XtArgVal) 18}, + }; + + for (j=0; j < toc->num_scrns; j++) { + scrn = toc->scrn[j]; + + /* Find the sequence menu and the number of entries in it. */ + + name = MenuBoxButtons[XMH_SEQUENCE].button_name; + button = BBoxFindButtonNamed(scrn->mainbuttons, name); + menu = BBoxMenuOfButton(button); + XtSetArg(query_args[0], XtNnumChildren, &numChildren); + XtSetArg(query_args[1], XtNchildren, &children); + XtGetValues(menu, query_args, (Cardinal) 2); + n = MenuBoxButtons[XMH_SEQUENCE].num_entries; + if (strcmp(XtName(children[0]), "menuLabel") == 0) + n++; + + /* Erase the current check mark. */ + + for (i=(n-1); i < numChildren; i++) + ToggleMenuItem(children[i], False); + + /* Delete any entries which should be deleted. */ + + for (i=n; i < numChildren; i++) + if (! TocGetSeqNamed(toc, XtName(children[i]))) + XtDestroyWidget(children[i]); + + /* Create any entries which should be created. */ + + callbacks[0].closure = (XtPointer) scrn; + for (i=1; i < toc->numsequences; i++) + if (! XtNameToWidget(menu, toc->seqlist[i]->name)) + XtCreateManagedWidget(toc->seqlist[i]->name, smeBSBObjectClass, + menu, args, XtNumber(args)); + + /* Set the check mark. */ + + name = toc->viewedseq->name; + if ((item = XtNameToWidget(menu, name)) != NULL) + ToggleMenuItem(item, True); + } + TocSetSelectedSequence(toc, toc->viewedseq); +} + + +void TUScanFileForToc(Toc toc) +{ + Scrn scrn; + char **argv, str[100]; + if (toc) { + TUGetFullFolderInfo(toc); + if (toc->num_scrns) scrn = toc->scrn[0]; + else scrn = scrnList[0]; + + (void) sprintf(str, "Rescanning %s", toc->foldername); + ChangeLabel(scrn->toclabel, str); + + argv = MakeArgv(5); + argv[0] = "scan"; + argv[1] = TocMakeFolderName(toc); + argv[2] = "-width"; + (void) sprintf(str, "%d", app_resources.toc_width); + argv[3] = str; + argv[4] = "-noheader"; + DoCommand(argv, (char *) NULL, toc->scanfile); + XtFree(argv[1]); + XtFree((char *) argv); + + toc->needslabelupdate = True; + toc->validity = valid; + toc->curmsg = NULL; /* Get cur msg somehow! %%% */ + } +} + + + +int TUGetMsgPosition(Toc toc, Msg msg) +{ + int msgid, h = 0, l, m; + char str[100]; + static Boolean ordered = True; + msgid = msg->msgid; + if (ordered) { + l = 0; + h = toc->nummsgs - 1; + while (l < h - 1) { + m = (l + h) / 2; + if (toc->msgs[m]->msgid > msgid) + h = m; + else + l = m; + } + if (toc->msgs[l] == msg) return l; + if (toc->msgs[h] == msg) return h; + } + ordered = False; + for (l = 0; l < toc->nummsgs; l++) { + if (msgid == toc->msgs[l]->msgid) return l; + } + (void) sprintf(str, + "TUGetMsgPosition search failed! hi=%d, lo=%d, msgid=%d", + h, l, msgid); + Punt(str); + return 0; /* Keep lint happy. */ +} + + +void TUResetTocLabel(Scrn scrn) +{ + char str[500]; + Toc toc; + if (scrn) { + toc = scrn->toc; + if (toc == NULL) + (void) strcpy(str, " "); + else { + if (toc->stopupdate) { + toc->needslabelupdate = TRUE; + return; + } + (void) sprintf(str, "%s:%s", toc->foldername, + toc->viewedseq->name); + toc->needslabelupdate = FALSE; + } + ChangeLabel((Widget) scrn->toclabel, str); + } +} + + +/* A major toc change has occured; redisplay it. (This also should work even + if we now have a new source to display stuff from.) */ + +void TURedisplayToc(Scrn scrn) +{ + Toc toc; + Widget source; + if (scrn != NULL && scrn->tocwidget != NULL) { + toc = scrn->toc; + if (toc) { + if (toc->stopupdate) { + toc->needsrepaint = TRUE; + return; + } + XawTextDisableRedisplay(scrn->tocwidget); + source = XawTextGetSource(scrn->tocwidget); + if (toc->force_reset || source != toc->source) { + XawTextSetSource(scrn->tocwidget, toc->source, + (XawTextPosition) 0); + toc->force_reset = False; /* %%% temporary */ + } + TocSetCurMsg(toc, TocGetCurMsg(toc)); + XawTextEnableRedisplay(scrn->tocwidget); + TUCheckSequenceMenu(toc); + toc->needsrepaint = FALSE; + } else { + XawTextSetSource(scrn->tocwidget, PNullSource, (XawTextPosition) 0); + } + } +} + + +void TULoadSeqLists(Toc toc) +{ + Sequence seq; + FILEPTR fid; + char str[500], *ptr, *ptr2, viewed[500], selected[500]; + int i; + if (toc->viewedseq) (void) strcpy(viewed, toc->viewedseq->name); + else *viewed = 0; + if (toc->selectseq) (void) strcpy(selected, toc->selectseq->name); + else *selected = 0; + for (i = 0; i < toc->numsequences; i++) { + seq = toc->seqlist[i]; + XtFree((char *) seq->name); + if (seq->mlist) FreeMsgList(seq->mlist); + XtFree((char *)seq); + } + toc->numsequences = 1; + toc->seqlist = (Sequence *) XtRealloc((char *) toc->seqlist, + (Cardinal) sizeof(Sequence)); + seq = toc->seqlist[0] = XtNew(SequenceRec); + seq->name = XtNewString("all"); + seq->mlist = NULL; + toc->viewedseq = seq; + toc->selectseq = seq; + (void) sprintf(str, "%s/.mh_sequences", toc->path); + fid = myfopen(str, "r"); + if (fid) { + while ((ptr = ReadLine(fid))) { + ptr2 = strchr(ptr, ':'); + if (ptr2) { + *ptr2 = 0; + if (strcmp(ptr, "all") != 0 && + strcmp(ptr, "cur") != 0 && + strcmp(ptr, "unseen") != 0) { + toc->numsequences++; + toc->seqlist = (Sequence *) + XtRealloc((char *) toc->seqlist, (Cardinal) + toc->numsequences * sizeof(Sequence)); + seq = toc->seqlist[toc->numsequences - 1] = + XtNew(SequenceRec); + seq->name = XtNewString(ptr); + seq->mlist = StringToMsgList(toc, ptr2 + 1); + if (strcmp(seq->name, viewed) == 0) { + toc->viewedseq = seq; + *viewed = 0; + } + if (strcmp(seq->name, selected) == 0) { + toc->selectseq = seq; + *selected = 0; + } + } + } + } + (void) myfclose(fid); + } +} + + + +/* Refigure what messages are visible. */ + +void TURefigureWhatsVisible(Toc toc) +{ + MsgList mlist; + Msg msg, oldcurmsg; + int i; + int w, changed, newval, msgid; + Sequence seq = toc->viewedseq; + mlist = seq->mlist; + oldcurmsg = toc->curmsg; + TocSetCurMsg(toc, (Msg)NULL); + w = 0; + changed = FALSE; + + for (i = 0; i < toc->nummsgs; i++) { + msg = toc->msgs[i]; + msgid = msg->msgid; + while (mlist && mlist->msglist[w] && mlist->msglist[w]->msgid < msgid) + w++; + newval = (!mlist + || (mlist->msglist[w] && mlist->msglist[w]->msgid == msgid)); + if (newval != msg->visible) { + changed = TRUE; + msg->visible = newval; + } + } + if (changed) { + TURefigureTocPositions(toc); + if (oldcurmsg) { + if (!oldcurmsg->visible) { + toc->curmsg = TocMsgAfter(toc, oldcurmsg); + if (toc->curmsg == NULL) + toc->curmsg = TocMsgBefore(toc, oldcurmsg); + } else toc->curmsg = oldcurmsg; + } + for (i=0 ; i<toc->num_scrns ; i++) + TURedisplayToc(toc->scrn[i]); + } else TocSetCurMsg(toc, oldcurmsg); + for (i=0 ; i<toc->num_scrns ; i++) + TUResetTocLabel(toc->scrn[i]); +} + + +/* (Re)load the toc from the scanfile. If reloading, this makes efforts to + keep the fates of msgs, and to keep msgs that are being edited. Note that + this routine must know of all places that msg ptrs are stored; it expects + them to be kept only in tocs, in scrns, and in msg sequences. */ + +#define SeemsIdentical(msg1, msg2) ((msg1)->msgid == (msg2)->msgid && \ + ((msg1)->temporary || (msg2)->temporary ||\ + strcmp((msg1)->buf, (msg2)->buf) == 0)) + +void TULoadTocFile(Toc toc) +{ + int maxmsgs, l, orignummsgs, i, j, origcurmsgid; + FILEPTR fid; + XawTextPosition position; + char *ptr; + Msg msg, curmsg; + Msg *origmsgs; + int bufsiz = app_resources.toc_width + 1; + static char *buf; + + if (!buf) + buf = XtMalloc((Cardinal) bufsiz); + TocStopUpdate(toc); + toc->lastreaddate = LastModifyDate(toc->scanfile); + if (toc->curmsg) { + origcurmsgid = toc->curmsg->msgid; + TocSetCurMsg(toc, (Msg)NULL); + } else origcurmsgid = 0; /* The "default" current msg; 0 means none */ + fid = FOpenAndCheck(toc->scanfile, "r"); + maxmsgs = orignummsgs = toc->nummsgs; + if (maxmsgs == 0) maxmsgs = 100; + toc->nummsgs = 0; + origmsgs = toc->msgs; + toc->msgs = (Msg *) XtMalloc((Cardinal) maxmsgs * sizeof(Msg)); + position = 0; + i = 0; + curmsg = NULL; + while ((ptr = fgets(buf, bufsiz, fid))) { + toc->msgs[toc->nummsgs++] = msg = XtNew(MsgRec); + bzero((char *) msg, sizeof(MsgRec)); + msg->toc = toc; + msg->position = position; + msg->length = l = strlen(ptr); + position += l; + if (l == app_resources.toc_width && buf[bufsiz-2] != '\n') { + buf[bufsiz-2] = '\n'; + msg->buf = strcpy(XtMalloc((Cardinal) ++l), ptr); + msg->msgid = atoi(ptr); + do + ptr = fgets(buf, bufsiz, fid); + while (ptr && (int) strlen(ptr) == app_resources.toc_width + && buf[bufsiz-2] != '\n'); + } else { + msg->buf = strcpy(XtMalloc((Cardinal) ++l), ptr); + msg->msgid = atoi(ptr); + } + if (msg->msgid == origcurmsgid) + curmsg = msg; + msg->buf[MARKPOS] = ' '; + msg->changed = FALSE; + msg->fate = Fignore; + msg->desttoc = NULL; + msg->visible = TRUE; + if (toc->nummsgs >= maxmsgs) { + maxmsgs += 100; + toc->msgs = (Msg *) XtRealloc((char *) toc->msgs, + (Cardinal) maxmsgs * sizeof(Msg)); + } + while (i < orignummsgs && origmsgs[i]->msgid < msg->msgid) i++; + if (i < orignummsgs) { + origmsgs[i]->buf[MARKPOS] = ' '; + if (SeemsIdentical(origmsgs[i], msg)) + MsgSetFate(msg, origmsgs[i]->fate, origmsgs[i]->desttoc); + } + } + toc->length = toc->origlength = toc->lastPos = position; + toc->msgs = (Msg *) XtRealloc((char *) toc->msgs, + (Cardinal) toc->nummsgs * sizeof(Msg)); + (void) myfclose(fid); + if ( (toc->source == NULL) && ( toc->num_scrns > 0 ) ) { + Arg args[1]; + + XtSetArg(args[0], XtNtoc, toc); + toc->source = XtCreateWidget("tocSource", tocSourceWidgetClass, + toc->scrn[0]->tocwidget, + args, (Cardinal) 1); + } + for (i=0 ; i<numScrns ; i++) { + msg = scrnList[i]->msg; + if (msg && msg->toc == toc) { + for (j=0 ; j<toc->nummsgs ; j++) { + if (SeemsIdentical(toc->msgs[j], msg)) { + msg->position = toc->msgs[j]->position; + msg->visible = TRUE; + ptr = toc->msgs[j]->buf; + l = toc->msgs[j]->length; + *(toc->msgs[j]) = *msg; + toc->msgs[j]->buf = ptr; + toc->msgs[j]->length = l; + scrnList[i]->msg = toc->msgs[j]; + break; + } + } + if (j >= toc->nummsgs) { + msg->temporary = FALSE; /* Don't try to auto-delete msg. */ + MsgSetScrnForce(msg, (Scrn) NULL); + } + } + } + for (i=0 ; i<orignummsgs ; i++) + MsgFree(origmsgs[i]); + XtFree((char *)origmsgs); + TocSetCurMsg(toc, curmsg); + TULoadSeqLists(toc); + TocStartUpdate(toc); +} + + +void TUSaveTocFile(Toc toc) +{ + Msg msg; + int fid; + int i; + XawTextPosition position; + char c; + if (toc->stopupdate) { + toc->needscachesave = TRUE; + return; + } + fid = -1; + position = 0; + for (i = 0; i < toc->nummsgs; i++) { + msg = toc->msgs[i]; + if (fid < 0 && msg->changed) { + fid = myopen(toc->scanfile, O_RDWR, 0666); + (void) lseek(fid, (long)position, 0); + } + if (fid >= 0) { + c = msg->buf[MARKPOS]; + msg->buf[MARKPOS] = ' '; + (void) write(fid, msg->buf, msg->length); + msg->buf[MARKPOS] = c; + } + position += msg->length; + } + if (fid < 0 && toc->length != toc->origlength) + fid = myopen(toc->scanfile, O_RDWR, 0666); + if (fid >= 0) { +#if defined(SYSV) && (defined(i386) || defined(MOTOROLA)) + (void) ftruncate_emu(fid, toc->length, toc->scanfile); +#else + (void) ftruncate(fid, toc->length); + myclose(fid); +#endif + toc->origlength = toc->length; + } + toc->needscachesave = FALSE; + toc->lastreaddate = LastModifyDate(toc->scanfile); +} + + +static Boolean UpdateScanFile( + XtPointer client_data) /* Toc */ +{ + Toc toc = (Toc)client_data; + int i; + + if (app_resources.block_events_on_busy) ShowBusyCursor(); + + TUScanFileForToc(toc); + TULoadTocFile(toc); + + for (i=0 ; i<toc->num_scrns ; i++) + TURedisplayToc(toc->scrn[i]); + + if (app_resources.block_events_on_busy) UnshowBusyCursor(); + + return True; +} + + +void TUEnsureScanIsValidAndOpen(Toc toc, Boolean delay) +{ + if (toc) { + TUGetFullFolderInfo(toc); + if (TUScanFileOutOfDate(toc)) { + if (!delay) + UpdateScanFile((XtPointer)toc); + else { + /* this is a hack to get the screen mapped before + * spawning the subprocess (and blocking). + * Need to make sure the scanfile exists at this point. + */ + int fid = myopen(toc->scanfile, O_RDWR|O_CREAT, 0666); + myclose(fid); + XtAppAddWorkProc(XtWidgetToApplicationContext(toplevel), + UpdateScanFile, + (XtPointer)toc); + } + } + if (toc->source == NULL) + TULoadTocFile(toc); + } +} + + + +/* Refigure all the positions, based on which lines are visible. */ + +void TURefigureTocPositions(Toc toc) +{ + int i; + Msg msg; + XawTextPosition position, length; + position = length = 0; + for (i=0; i<toc->nummsgs ; i++) { + msg = toc->msgs[i]; + msg->position = position; + if (msg->visible) position += msg->length; + length += msg->length; + } + toc->lastPos = position; + toc->length = length; +} + + + +/* Make sure we've loaded ALL the folder info for this toc, including its + path and sequence lists. */ + +void TUGetFullFolderInfo(Toc toc) +{ + char str[500]; + if (! toc->scanfile) { + if (! toc->path) { + /* usually preset by TocFolderExists */ + (void) sprintf(str, "%s/%s", app_resources.mail_path, + toc->foldername); + toc->path = XtNewString(str); + } + (void) sprintf(str, "%s/.xmhcache", toc->path); + toc->scanfile = XtNewString(str); + toc->lastreaddate = LastModifyDate(toc->scanfile); + if (TUScanFileOutOfDate(toc)) + toc->validity = invalid; + else { + toc->validity = valid; + TULoadTocFile(toc); + } + } +} + +/* Append a message to the end of the toc. It has the given scan line. This + routine will figure out the message number, and change the scan line + accordingly. */ + +Msg TUAppendToc(Toc toc, char *ptr) +{ + Msg msg; + int msgid; + + TUGetFullFolderInfo(toc); + if (toc->validity != valid) + return NULL; + + if (toc->nummsgs > 0) + msgid = toc->msgs[toc->nummsgs - 1]->msgid + 1; + else + msgid = 1; + (toc->nummsgs)++; + toc->msgs = (Msg *) XtRealloc((char *) toc->msgs, + (Cardinal) toc->nummsgs * sizeof(Msg)); + toc->msgs[toc->nummsgs - 1] = msg = XtNew(MsgRec); + bzero((char *) msg, (int) sizeof(MsgRec)); + msg->toc = toc; + msg->buf = XtNewString(ptr); + if (msgid >= 10000) + msgid %= 10000; + (void)sprintf(msg->buf, "%4d", msgid); + msg->buf[MARKPOS] = ' '; + msg->msgid = msgid; + msg->position = toc->lastPos; + msg->length = strlen(ptr); + msg->changed = TRUE; + msg->fate = Fignore; + msg->desttoc = NULL; + if (toc->viewedseq == toc->seqlist[0]) { + msg->visible = TRUE; + toc->lastPos += msg->length; + } + else + msg->visible = FALSE; + toc->length += msg->length; + if ( (msg->visible) && (toc->source != NULL) ) + TSourceInvalid(toc, msg->position, msg->length); + TUSaveTocFile(toc); + return msg; +} |