source: trunk/third/xmh/tocutil.c @ 9658

Revision 9658, 16.1 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9657, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * $XConsortium: tocutil.c,v 2.57 91/07/31 01:10:23 keith Exp $
3 *
4 *
5 *                      COPYRIGHT 1987, 1989
6 *                 DIGITAL EQUIPMENT CORPORATION
7 *                     MAYNARD, MASSACHUSETTS
8 *                      ALL RIGHTS RESERVED.
9 *
10 * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
11 * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
12 * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
13 * ANY PURPOSE.  IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
14 *
15 * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT
16 * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN
17 * ADDITION TO THAT SET FORTH ABOVE.
18 *
19 * Permission to use, copy, modify, and distribute this software and its
20 * documentation for any purpose and without fee is hereby granted, provided
21 * that the above copyright notice appear in all copies and that both that
22 * copyright notice and this permission notice appear in supporting
23 * documentation, and that the name of Digital Equipment Corporation not be
24 * used in advertising or publicity pertaining to distribution of the software
25 * without specific, written prior permission.
26 */
27
28/* tocutil.c -- internal routines for toc stuff. */
29
30#include "xmh.h"
31#include "toc.h"
32#include "tocutil.h"
33#include "tocintrnl.h"
34
35#ifdef X_NOT_POSIX
36extern long lseek();
37#endif
38
39Toc TUMalloc()
40{
41    Toc toc;
42    toc = XtNew(TocRec);
43    bzero((char *)toc, (int) sizeof(TocRec));
44    toc->msgs = (Msg *) NULL;
45    toc->seqlist = (Sequence *) NULL;
46    toc->validity = unknown;
47    return toc;
48}
49
50
51/* Returns TRUE if the scan file for the given toc is out of date. */
52
53int TUScanFileOutOfDate(toc)
54  Toc toc;
55{
56    return LastModifyDate(toc->path) > toc->lastreaddate;
57}
58
59
60/* Make sure the sequence menu entries correspond exactly to the sequences
61 * for this toc.
62 */
63
64void TUCheckSequenceMenu(toc)
65    Toc         toc;
66{
67    Scrn        scrn;
68    register int i, n;
69    Arg         query_args[2];
70    char        *name;
71    int         j, numChildren;
72    Widget      menu, item;
73    Button      button;
74    WidgetList  children;
75
76    static XtCallbackRec callbacks[] = {
77        { DoSelectSequence,             (XtPointer) NULL},
78        { (XtCallbackProc) NULL,        (XtPointer) NULL},
79    };
80    static Arg  args[] = {
81        { XtNcallback,                  (XtArgVal) callbacks},
82        { XtNleftMargin,                (XtArgVal) 18},
83    };
84
85    for (j=0; j < toc->num_scrns; j++) {
86        scrn = toc->scrn[j];
87
88        /* Find the sequence menu and the number of entries in it. */
89
90        name = MenuBoxButtons[XMH_SEQUENCE].button_name;
91        button = BBoxFindButtonNamed(scrn->mainbuttons, name);
92        menu = BBoxMenuOfButton(button);
93        XtSetArg(query_args[0], XtNnumChildren, &numChildren);
94        XtSetArg(query_args[1], XtNchildren, &children);
95        XtGetValues(menu, query_args, (Cardinal) 2);
96        n = MenuBoxButtons[XMH_SEQUENCE].num_entries;
97        if (strcmp(XtName(children[0]), "menuLabel") == 0)
98            n++;
99
100        /* Erase the current check mark. */
101
102        for (i=(n-1); i < numChildren; i++)
103            ToggleMenuItem(children[i], False);
104
105        /* Delete any entries which should be deleted. */
106
107        for (i=n; i < numChildren; i++)
108            if (! TocGetSeqNamed(toc, XtName(children[i])))
109                XtDestroyWidget(children[i]);
110
111        /* Create any entries which should be created. */
112       
113        callbacks[0].closure = (XtPointer) scrn;
114        for (i=1; i < toc->numsequences; i++)
115            if (! XtNameToWidget(menu, toc->seqlist[i]->name))
116                XtCreateManagedWidget(toc->seqlist[i]->name, smeBSBObjectClass,
117                                      menu, args, XtNumber(args));
118
119        /* Set the check mark. */
120
121        name = toc->viewedseq->name;
122        if ((item = XtNameToWidget(menu, name)) != NULL)
123            ToggleMenuItem(item, True);
124    }
125    TocSetSelectedSequence(toc, toc->viewedseq);
126}
127
128
129void TUScanFileForToc(toc)
130  Toc toc;
131{
132    Scrn scrn;
133    char  **argv, str[100];
134    if (toc) {
135        TUGetFullFolderInfo(toc);
136        if (toc->num_scrns) scrn = toc->scrn[0];
137        else scrn = scrnList[0];
138
139        (void) sprintf(str, "Rescanning %s", toc->foldername);
140        ChangeLabel(scrn->toclabel, str);
141
142        argv = MakeArgv(5);
143        argv[0] = "scan";
144        argv[1] = TocMakeFolderName(toc);
145        argv[2] = "-width";
146        (void) sprintf(str, "%d", app_resources.toc_width);
147        argv[3] = str;
148        argv[4] = "-noheader";
149        DoCommand(argv, (char *) NULL, toc->scanfile);
150        XtFree(argv[1]);
151        XtFree((char *) argv);
152
153        toc->needslabelupdate = True;
154        toc->validity = valid;
155        toc->curmsg = NULL;     /* Get cur msg somehow! %%% */
156    }
157}
158
159
160
161int TUGetMsgPosition(toc, msg)
162  Toc toc;
163  Msg msg;
164{
165    int msgid, h, l, m;
166    char str[100];
167    static Boolean ordered = True;
168    msgid = msg->msgid;
169    if (ordered) {
170        l = 0;
171        h = toc->nummsgs - 1;
172        while (l < h - 1) {
173            m = (l + h) / 2;
174            if (toc->msgs[m]->msgid > msgid)
175                h = m;
176            else
177                l = m;
178        }
179        if (toc->msgs[l] == msg) return l;
180        if (toc->msgs[h] == msg) return h;
181    }
182    ordered = False;
183    for (l = 0; l < toc->nummsgs; l++) {
184        if (msgid == toc->msgs[l]->msgid) return l;
185    }
186    (void) sprintf(str,
187                   "TUGetMsgPosition search failed! hi=%d, lo=%d, msgid=%d",
188                   h, l, msgid);
189    Punt(str);
190    return 0; /* Keep lint happy. */
191}
192
193
194void TUResetTocLabel(scrn)
195  Scrn scrn;
196{
197    char str[500];
198    Toc toc;
199    if (scrn) {
200        toc = scrn->toc;
201        if (toc == NULL)
202            (void) strcpy(str, " ");
203        else {
204            if (toc->stopupdate) {
205                toc->needslabelupdate = TRUE;
206                return;
207            }
208            (void) sprintf(str, "%s:%s", toc->foldername,
209                           toc->viewedseq->name);
210            toc->needslabelupdate = FALSE;
211        }
212        ChangeLabel((Widget) scrn->toclabel, str);
213    }
214}
215
216
217/* A major toc change has occured; redisplay it.  (This also should work even
218   if we now have a new source to display stuff from.) */
219
220void TURedisplayToc(scrn)
221  Scrn scrn;
222{
223    Toc toc;
224    Widget source;
225    if (scrn != NULL && scrn->tocwidget != NULL) {
226        toc = scrn->toc;
227        if (toc) {
228            if (toc->stopupdate) {
229                toc->needsrepaint = TRUE;
230                return;
231            }
232            XawTextDisableRedisplay(scrn->tocwidget);
233            source = XawTextGetSource(scrn->tocwidget);
234            if (toc->force_reset || source != toc->source) {
235                XawTextSetSource(scrn->tocwidget, toc->source,
236                                 (XawTextPosition) 0);
237                toc->force_reset = False; /* %%% temporary */
238            }
239            TocSetCurMsg(toc, TocGetCurMsg(toc));
240            XawTextEnableRedisplay(scrn->tocwidget);
241            TUCheckSequenceMenu(toc);
242            toc->needsrepaint = FALSE;
243        } else {
244            XawTextSetSource(scrn->tocwidget, PNullSource, (XawTextPosition) 0);
245        }
246    }
247}
248
249
250void TULoadSeqLists(toc)
251  Toc toc;
252{
253    Sequence seq;
254    FILEPTR fid;
255    char    str[500], *ptr, *ptr2, viewed[500], selected[500];
256    int     i;
257    if (toc->viewedseq) (void) strcpy(viewed, toc->viewedseq->name);
258    else *viewed = 0;
259    if (toc->selectseq) (void) strcpy(selected, toc->selectseq->name);
260    else *selected = 0;
261    for (i = 0; i < toc->numsequences; i++) {
262        seq = toc->seqlist[i];
263        XtFree((char *) seq->name);
264        if (seq->mlist) FreeMsgList(seq->mlist);
265        XtFree((char *)seq);
266    }
267    toc->numsequences = 1;
268    toc->seqlist = (Sequence *) XtRealloc((char *) toc->seqlist,
269                                          (Cardinal) sizeof(Sequence));
270    seq = toc->seqlist[0] = XtNew(SequenceRec);
271    seq->name = XtNewString("all");
272    seq->mlist = NULL;
273    toc->viewedseq = seq;
274    toc->selectseq = seq;
275    (void) sprintf(str, "%s/.mh_sequences", toc->path);
276    fid = myfopen(str, "r");
277    if (fid) {
278        while (ptr = ReadLine(fid)) {
279            ptr2 = index(ptr, ':');
280            if (ptr2) {
281                *ptr2 = 0;
282                if (strcmp(ptr, "all") != 0 &&
283                    strcmp(ptr, "cur") != 0 &&
284                    strcmp(ptr, "unseen") != 0) {
285                    toc->numsequences++;
286                    toc->seqlist = (Sequence *)
287                        XtRealloc((char *) toc->seqlist, (Cardinal)
288                                  toc->numsequences * sizeof(Sequence));
289                    seq = toc->seqlist[toc->numsequences - 1] =
290                        XtNew(SequenceRec);
291                    seq->name = XtNewString(ptr);
292                    seq->mlist = StringToMsgList(toc, ptr2 + 1);
293                    if (strcmp(seq->name, viewed) == 0) {
294                        toc->viewedseq = seq;
295                        *viewed = 0;
296                    }
297                    if (strcmp(seq->name, selected) == 0) {
298                        toc->selectseq = seq;
299                        *selected = 0;
300                    }
301                }
302            }
303        }
304        (void) myfclose(fid);
305    }
306}
307
308
309
310/* Refigure what messages are visible. */
311
312void TURefigureWhatsVisible(toc)
313Toc toc;
314{
315    MsgList mlist;
316    Msg msg, oldcurmsg;
317    int     i, w, changed, newval, msgid;
318    Sequence seq = toc->viewedseq;
319    mlist = seq->mlist;
320    oldcurmsg = toc->curmsg;
321    TocSetCurMsg(toc, (Msg)NULL);
322    w = 0;
323    changed = FALSE;
324
325    for (i = 0; i < toc->nummsgs; i++) {
326        msg = toc->msgs[i];
327        msgid = msg->msgid;
328        while (mlist && mlist->msglist[w] && mlist->msglist[w]->msgid < msgid)
329            w++;
330        newval = (!mlist
331                  || (mlist->msglist[w] && mlist->msglist[w]->msgid == msgid));
332        if (newval != msg->visible) {
333            changed = TRUE;
334            msg->visible = newval;
335        }
336    }
337    if (changed) {
338        TURefigureTocPositions(toc);
339        if (oldcurmsg) {
340            if (!oldcurmsg->visible) {
341                toc->curmsg = TocMsgAfter(toc, oldcurmsg);
342                if (toc->curmsg == NULL)
343                    toc->curmsg = TocMsgBefore(toc, oldcurmsg);
344            } else toc->curmsg = oldcurmsg;
345        }
346        for (i=0 ; i<toc->num_scrns ; i++)
347            TURedisplayToc(toc->scrn[i]);
348    } else TocSetCurMsg(toc, oldcurmsg);
349    for (i=0 ; i<toc->num_scrns ; i++)
350        TUResetTocLabel(toc->scrn[i]);
351}
352
353
354/* (Re)load the toc from the scanfile.  If reloading, this makes efforts to
355   keep the fates of msgs, and to keep msgs that are being edited.  Note that
356   this routine must know of all places that msg ptrs are stored; it expects
357   them to be kept only in tocs, in scrns, and in msg sequences. */
358
359#define SeemsIdentical(msg1, msg2) ((msg1)->msgid == (msg2)->msgid &&         \
360                                    ((msg1)->temporary || (msg2)->temporary ||\
361                                     strcmp((msg1)->buf, (msg2)->buf) == 0))
362
363void TULoadTocFile(toc)
364  Toc toc;
365{
366    int maxmsgs, l, orignummsgs, i, j, origcurmsgid;
367    FILEPTR fid;
368    XawTextPosition position;
369    char *ptr;
370    Msg msg, curmsg;
371    Msg *origmsgs;
372    int bufsiz = app_resources.toc_width + 1;
373    static char *buf;
374
375    if (!buf)
376        buf = XtMalloc((Cardinal) bufsiz);
377    TocStopUpdate(toc);
378    toc->lastreaddate = LastModifyDate(toc->scanfile);
379    if (toc->curmsg) {
380        origcurmsgid = toc->curmsg->msgid;
381        TocSetCurMsg(toc, (Msg)NULL);
382    } else origcurmsgid = 0;  /* The "default" current msg; 0 means none */
383    fid = FOpenAndCheck(toc->scanfile, "r");
384    maxmsgs = orignummsgs = toc->nummsgs;
385    if (maxmsgs == 0) maxmsgs = 100;
386    toc->nummsgs = 0;
387    origmsgs = toc->msgs;
388    toc->msgs = (Msg *) XtMalloc((Cardinal) maxmsgs * sizeof(Msg));
389    position = 0;
390    i = 0;
391    curmsg = NULL;
392    while (ptr = fgets(buf, bufsiz, fid)) {
393        toc->msgs[toc->nummsgs++] = msg = XtNew(MsgRec);
394        bzero((char *) msg, sizeof(MsgRec));
395        msg->toc = toc;
396        msg->position = position;
397        msg->length = l = strlen(ptr);
398        position += l;
399        if (l == app_resources.toc_width && buf[bufsiz-2] != '\n') {
400            buf[bufsiz-2] = '\n';
401            msg->buf = strcpy(XtMalloc((Cardinal) ++l), ptr);
402            msg->msgid = atoi(ptr);
403            do
404                ptr = fgets(buf, bufsiz, fid);
405            while (ptr && strlen(ptr) == app_resources.toc_width
406                   && buf[bufsiz-2] != '\n');
407        } else {
408            msg->buf = strcpy(XtMalloc((Cardinal) ++l), ptr);
409            msg->msgid = atoi(ptr);
410        }
411        if (msg->msgid == origcurmsgid)
412            curmsg = msg;
413        msg->buf[MARKPOS] = ' ';
414        msg->changed = FALSE;
415        msg->fate = Fignore;
416        msg->desttoc = NULL;
417        msg->visible = TRUE;
418        if (toc->nummsgs >= maxmsgs) {
419            maxmsgs += 100;
420            toc->msgs = (Msg *) XtRealloc((char *) toc->msgs,
421                                          (Cardinal) maxmsgs * sizeof(Msg));
422        }
423        while (i < orignummsgs && origmsgs[i]->msgid < msg->msgid) i++;
424        if (i < orignummsgs) {
425            origmsgs[i]->buf[MARKPOS] = ' ';
426            if (SeemsIdentical(origmsgs[i], msg))
427                MsgSetFate(msg, origmsgs[i]->fate, origmsgs[i]->desttoc);
428        }
429    }
430    toc->length = toc->origlength = toc->lastPos = position;
431    toc->msgs = (Msg *) XtRealloc((char *) toc->msgs,
432                                  (Cardinal) toc->nummsgs * sizeof(Msg));
433    (void) myfclose(fid);
434    if ( (toc->source == NULL) && ( toc->num_scrns > 0 ) ) {
435        Arg args[1];
436
437        XtSetArg(args[0], XtNtoc, toc);
438        toc->source = XtCreateWidget("tocSource", tocSourceWidgetClass,
439                                     toc->scrn[0]->tocwidget,
440                                     args, (Cardinal) 1);
441    }
442    for (i=0 ; i<numScrns ; i++) {
443        msg = scrnList[i]->msg;
444        if (msg && msg->toc == toc) {
445            for (j=0 ; j<toc->nummsgs ; j++) {
446                if (SeemsIdentical(toc->msgs[j], msg)) {
447                    msg->position = toc->msgs[j]->position;
448                    msg->visible = TRUE;
449                    ptr = toc->msgs[j]->buf;
450                    l = toc->msgs[j]->length;
451                    *(toc->msgs[j]) = *msg;
452                    toc->msgs[j]->buf = ptr;
453                    toc->msgs[j]->length = l;
454                    scrnList[i]->msg = toc->msgs[j];
455                    break;
456                }
457            }
458            if (j >= toc->nummsgs) {
459                msg->temporary = FALSE; /* Don't try to auto-delete msg. */
460                MsgSetScrnForce(msg, (Scrn) NULL);
461            }
462        }
463    }
464    for (i=0 ; i<orignummsgs ; i++)
465        MsgFree(origmsgs[i]);
466    XtFree((char *)origmsgs);
467    TocSetCurMsg(toc, curmsg);
468    TULoadSeqLists(toc);
469    TocStartUpdate(toc);
470}
471
472
473void TUSaveTocFile(toc)
474  Toc toc;
475{
476    Msg msg;
477    int fid;
478    int i;
479    XawTextPosition position;
480    char c;
481    if (toc->stopupdate) {
482        toc->needscachesave = TRUE;
483        return;
484    }
485    fid = -1;
486    position = 0;
487    for (i = 0; i < toc->nummsgs; i++) {
488        msg = toc->msgs[i];
489        if (fid < 0 && msg->changed) {
490            fid = myopen(toc->scanfile, O_RDWR, 0666);
491            (void) lseek(fid, (long)position, 0);
492        }
493        if (fid >= 0) {
494            c = msg->buf[MARKPOS];
495            msg->buf[MARKPOS] = ' ';
496            (void) write(fid, msg->buf, msg->length);
497            msg->buf[MARKPOS] = c;
498        }
499        position += msg->length;
500    }
501    if (fid < 0 && toc->length != toc->origlength)
502        fid = myopen(toc->scanfile, O_RDWR, 0666);
503    if (fid >= 0) {
504#if defined(SYSV) && (defined(SYSV386) || defined(MOTOROLA))
505        (void) ftruncate_emu(fid, toc->length, toc->scanfile);
506#else
507        (void) ftruncate(fid, toc->length);
508        (void) myclose(fid);
509#endif
510        toc->origlength = toc->length;
511    }
512    toc->needscachesave = FALSE;
513    toc->lastreaddate = LastModifyDate(toc->scanfile);
514}
515
516
517void TUEnsureScanIsValidAndOpen(toc)
518  Toc toc;
519{
520    if (toc) {
521        TUGetFullFolderInfo(toc);
522        if (TUScanFileOutOfDate(toc)) {
523            if (toc->source) {
524                XtFree((char *) toc->source);
525                toc->source = NULL;
526            }
527            TUScanFileForToc(toc);
528        }
529        if (toc->source == NULL)
530            TULoadTocFile(toc);
531        toc->validity = valid;
532    }
533}
534
535
536
537/* Refigure all the positions, based on which lines are visible. */
538
539void TURefigureTocPositions(toc)
540  Toc toc;
541{
542    int i;
543    Msg msg;
544    XawTextPosition position, length;
545    position = length = 0;
546    for (i=0; i<toc->nummsgs ; i++) {
547        msg = toc->msgs[i];
548        msg->position = position;
549        if (msg->visible) position += msg->length;
550        length += msg->length;
551    }
552    toc->lastPos = position;
553    toc->length = length;
554}
555
556
557
558/* Make sure we've loaded ALL the folder info for this toc, including its
559   path and sequence lists. */
560
561void TUGetFullFolderInfo(toc)
562  Toc toc;
563{
564    char str[500];
565    if (! toc->scanfile) {
566        if (! toc->path) {
567            /* usually preset by TocFolderExists */
568            (void) sprintf(str, "%s/%s", app_resources.mail_path,
569                           toc->foldername);
570            toc->path = XtNewString(str);
571        }
572        (void) sprintf(str, "%s/.xmhcache", toc->path);
573        toc->scanfile = XtNewString(str);
574        toc->lastreaddate = LastModifyDate(toc->scanfile);
575        if (TUScanFileOutOfDate(toc))
576            toc->validity = invalid;
577        else {
578            toc->validity = valid;
579            TULoadTocFile(toc);
580        }
581    }
582}
583
584/* Append a message to the end of the toc.  It has the given scan line.  This
585   routine will figure out the message number, and change the scan line
586   accordingly. */
587
588Msg TUAppendToc(toc, ptr)
589  Toc toc;
590  char *ptr;
591{
592    Msg msg;
593    int msgid, i;
594
595    TUGetFullFolderInfo(toc);
596    if (toc->validity != valid)
597        return NULL;
598           
599    if (toc->nummsgs > 0)
600        msgid = toc->msgs[toc->nummsgs - 1]->msgid + 1;
601    else
602        msgid = 1;
603    (toc->nummsgs)++;
604    toc->msgs = (Msg *) XtRealloc((char *) toc->msgs,
605                                  (Cardinal) toc->nummsgs * sizeof(Msg));
606    toc->msgs[toc->nummsgs - 1] = msg = XtNew(MsgRec);
607    bzero((char *) msg, (int) sizeof(MsgRec));
608    msg->toc = toc;
609    msg->buf = XtNewString(ptr);
610    if (msgid >= 10000)
611        msgid %= 10000;
612    (void)sprintf(msg->buf, "%4d", msgid);
613    msg->buf[MARKPOS] = ' ';
614    msg->msgid = msgid;
615    msg->position = toc->lastPos;
616    msg->length = strlen(ptr);
617    msg->changed = TRUE;
618    msg->fate = Fignore;
619    msg->desttoc = NULL;
620    if (toc->viewedseq == toc->seqlist[0]) {
621        msg->visible = TRUE;
622        toc->lastPos += msg->length;
623    }
624    else
625        msg->visible = FALSE;
626    toc->length += msg->length;
627    if ( (msg->visible) && (toc->source != NULL) )
628        TSourceInvalid(toc, msg->position, msg->length);
629    TUSaveTocFile(toc);
630    return msg;
631}
Note: See TracBrowser for help on using the repository browser.