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