toc.c revision d859ff80
1c9e2be55Smrg/* $XConsortium: toc.c,v 2.59 95/01/09 16:52:53 swick Exp $
2c9e2be55Smrg * $XFree86: xc/programs/xmh/toc.c,v 3.4 2001/10/28 03:34:39 tsi Exp $
3c9e2be55Smrg *
4c9e2be55Smrg *
5c9e2be55Smrg *			  COPYRIGHT 1987
6c9e2be55Smrg *		   DIGITAL EQUIPMENT CORPORATION
7c9e2be55Smrg *		       MAYNARD, MASSACHUSETTS
8c9e2be55Smrg *			ALL RIGHTS RESERVED.
9c9e2be55Smrg *
10c9e2be55Smrg * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
11c9e2be55Smrg * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
12c9e2be55Smrg * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
13c9e2be55Smrg * ANY PURPOSE.  IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
14c9e2be55Smrg *
15c9e2be55Smrg * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT
16c9e2be55Smrg * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN
17c9e2be55Smrg * ADDITION TO THAT SET FORTH ABOVE.
18c9e2be55Smrg *
19c9e2be55Smrg * Permission to use, copy, modify, and distribute this software and its
20c9e2be55Smrg * documentation for any purpose and without fee is hereby granted, provided
21c9e2be55Smrg * that the above copyright notice appear in all copies and that both that
22c9e2be55Smrg * copyright notice and this permission notice appear in supporting
23c9e2be55Smrg * documentation, and that the name of Digital Equipment Corporation not be
24c9e2be55Smrg * used in advertising or publicity pertaining to distribution of the software
25c9e2be55Smrg * without specific, written prior permission.
26c9e2be55Smrg */
27c9e2be55Smrg
28c9e2be55Smrg/* toc.c -- handle things in the toc widget. */
29c9e2be55Smrg
30c9e2be55Smrg#include "xmh.h"
31c9e2be55Smrg#include "tocintrnl.h"
32c9e2be55Smrg#include "toc.h"
33c9e2be55Smrg#include "tocutil.h"
34c9e2be55Smrg#include "actions.h"
35c9e2be55Smrg
36c9e2be55Smrg#include <sys/stat.h>
37c9e2be55Smrg
38c9e2be55Smrgstatic int IsDir(char *name)
39c9e2be55Smrg{
40c9e2be55Smrg    char str[500];
41c9e2be55Smrg    struct stat buf;
42c9e2be55Smrg    if (*name == '.')
43c9e2be55Smrg	return FALSE;
44c9e2be55Smrg    (void) sprintf(str, "%s/%s", app_resources.mail_path, name);
45c9e2be55Smrg    if (stat(str, &buf) /* failed */) return False;
46c9e2be55Smrg#ifdef S_ISDIR
47c9e2be55Smrg    return S_ISDIR(buf.st_mode);
48c9e2be55Smrg#else
49c9e2be55Smrg    return (buf.st_mode & S_IFMT) == S_IFDIR;
50c9e2be55Smrg#endif
51c9e2be55Smrg}
52c9e2be55Smrg
53c9e2be55Smrg
54c9e2be55Smrgstatic void MakeSureFolderExists(
55c9e2be55Smrg    char ***namelistptr,
56c9e2be55Smrg    int *numfoldersptr,
57c9e2be55Smrg    char *name)
58c9e2be55Smrg{
59c9e2be55Smrg    int i;
60c9e2be55Smrg    char str[200];
61c9e2be55Smrg    for (i=0 ; i<*numfoldersptr ; i++)
62c9e2be55Smrg	if (strcmp((*namelistptr)[i], name) == 0) return;
63c9e2be55Smrg    (void) sprintf(str, "%s/%s", app_resources.mail_path, name);
64c9e2be55Smrg    (void) mkdir(str, 0700);
65c9e2be55Smrg    *numfoldersptr = ScanDir(app_resources.mail_path, namelistptr, IsDir);
66c9e2be55Smrg    for (i=0 ; i<*numfoldersptr ; i++)
67c9e2be55Smrg	if (strcmp((*namelistptr)[i], name) == 0) return;
68c9e2be55Smrg    Punt("Can't create new mail folder!");
69c9e2be55Smrg}
70c9e2be55Smrg
71c9e2be55Smrg
72c9e2be55Smrgstatic void MakeSureSubfolderExists(
73c9e2be55Smrg    char ***		namelistptr,
74c9e2be55Smrg    int *		numfoldersptr,
75c9e2be55Smrg    char *		name)
76c9e2be55Smrg{
77c9e2be55Smrg    char folder[300];
78c9e2be55Smrg    char subfolder_path[300];
79c9e2be55Smrg    char *subfolder;
80c9e2be55Smrg    struct stat buf;
81c9e2be55Smrg
82c9e2be55Smrg    /* Make sure that the parent folder exists */
83c9e2be55Smrg
84c9e2be55Smrg    subfolder = strchr( strcpy(folder, name), '/');
85c9e2be55Smrg    *subfolder = '\0';
86c9e2be55Smrg    subfolder++;
87c9e2be55Smrg    MakeSureFolderExists(namelistptr, numfoldersptr, folder);
88d859ff80Smrg
89c9e2be55Smrg    /* The parent folder exists.  Make sure the subfolder exists. */
90c9e2be55Smrg
91c9e2be55Smrg    (void) sprintf(subfolder_path, "%s/%s", app_resources.mail_path, name);
92c9e2be55Smrg    if (stat(subfolder_path, &buf) /* failed */) {
93c9e2be55Smrg	(void) mkdir(subfolder_path, 0700);
94c9e2be55Smrg	if (stat(subfolder_path, &buf) /* failed */)
95c9e2be55Smrg	    Punt("Can't create new xmh subfolder!");
96c9e2be55Smrg    }
97c9e2be55Smrg#ifdef S_ISDIR
98c9e2be55Smrg    if (!S_ISDIR(buf.st_mode))
99c9e2be55Smrg#else
100c9e2be55Smrg    if ((buf.st_mode & S_IFMT) != S_IFDIR)
101c9e2be55Smrg#endif
102c9e2be55Smrg	Punt("Can't create new xmh subfolder!");
103c9e2be55Smrg}
104c9e2be55Smrg
105c9e2be55Smrgint TocFolderExists(Toc toc)
106c9e2be55Smrg{
107c9e2be55Smrg    struct stat buf;
108c9e2be55Smrg    if (! toc->path) {
109c9e2be55Smrg	char str[500];
110c9e2be55Smrg	(void) sprintf(str, "%s/%s", app_resources.mail_path, toc->foldername);
111c9e2be55Smrg	toc->path = XtNewString(str);
112c9e2be55Smrg    }
113c9e2be55Smrg    return ((stat(toc->path, &buf) == 0) &&
114c9e2be55Smrg#ifdef S_ISDIR
115c9e2be55Smrg	    (S_ISDIR(buf.st_mode)));
116c9e2be55Smrg#else
117c9e2be55Smrg	    ((buf.st_mode & S_IFMT) == S_IFDIR));
118c9e2be55Smrg#endif
119c9e2be55Smrg}
120c9e2be55Smrg
121c9e2be55Smrgstatic void LoadCheckFiles(void)
122c9e2be55Smrg{
123c9e2be55Smrg    FILE *fid;
124c9e2be55Smrg    char str[1024];
125c9e2be55Smrg
126c9e2be55Smrg    (void) sprintf(str, "%s/.xmhcheck", homeDir);
127c9e2be55Smrg    fid = myfopen(str, "r");
128c9e2be55Smrg    if (fid) {
129c9e2be55Smrg	int i;
130c9e2be55Smrg	char *ptr, *ptr2;
131c9e2be55Smrg
132c9e2be55Smrg	while ((ptr = ReadLine(fid))) {
133c9e2be55Smrg	    while (*ptr == ' ' || *ptr == '\t') ptr++;
134c9e2be55Smrg	    ptr2 = ptr;
135c9e2be55Smrg	    while (*ptr2 && *ptr2 != ' ' && *ptr2 != '\t') ptr2++;
136c9e2be55Smrg	    if (*ptr2 == 0) continue;
137c9e2be55Smrg	    *ptr2++ = 0;
138c9e2be55Smrg	    while (*ptr2 == ' ' || *ptr2 == '\t') ptr2++;
139c9e2be55Smrg	    if (*ptr2 == 0) continue;
140c9e2be55Smrg	    for (i=0 ; i<numFolders ; i++) {
141c9e2be55Smrg		if (strcmp(ptr, folderList[i]->foldername) == 0) {
142c9e2be55Smrg		    folderList[i]->incfile = XtNewString(ptr2);
143c9e2be55Smrg		    break;
144c9e2be55Smrg		}
145c9e2be55Smrg	    }
146c9e2be55Smrg	}
147c9e2be55Smrg	myfclose(fid);
148c9e2be55Smrg    } else if ( app_resources.initial_inc_file &&
149c9e2be55Smrg	       *app_resources.initial_inc_file)
150c9e2be55Smrg	InitialFolder->incfile = app_resources.initial_inc_file;
151c9e2be55Smrg}
152d859ff80Smrg
153c9e2be55Smrg
154c9e2be55Smrg/*	PUBLIC ROUTINES 	*/
155c9e2be55Smrg
156c9e2be55Smrg
157c9e2be55Smrg/* Read in the list of folders. */
158c9e2be55Smrg
159c9e2be55Smrgvoid TocInit(void)
160c9e2be55Smrg{
161c9e2be55Smrg    Toc toc;
162c9e2be55Smrg    char **namelist;
163c9e2be55Smrg    int i;
164c9e2be55Smrg    numFolders = ScanDir(app_resources.mail_path, &namelist, IsDir);
165c9e2be55Smrg    if (numFolders < 0) {
166c9e2be55Smrg	(void) mkdir(app_resources.mail_path, 0700);
167c9e2be55Smrg	numFolders = ScanDir(app_resources.mail_path, &namelist, IsDir);
168c9e2be55Smrg	if (numFolders < 0)
169c9e2be55Smrg	    Punt("Can't create or read mail directory!");
170c9e2be55Smrg    }
171c9e2be55Smrg    if (IsSubfolder(app_resources.initial_folder_name))
172c9e2be55Smrg	MakeSureSubfolderExists(&namelist, &numFolders,
173c9e2be55Smrg				app_resources.initial_folder_name);
174c9e2be55Smrg    else
175c9e2be55Smrg	MakeSureFolderExists(&namelist, &numFolders,
176c9e2be55Smrg			     app_resources.initial_folder_name);
177c9e2be55Smrg
178c9e2be55Smrg    if (IsSubfolder(app_resources.drafts_folder_name))
179c9e2be55Smrg	MakeSureSubfolderExists(&namelist, &numFolders,
180c9e2be55Smrg				app_resources.drafts_folder_name);
181c9e2be55Smrg    else
182c9e2be55Smrg	MakeSureFolderExists(&namelist, &numFolders,
183c9e2be55Smrg			     app_resources.drafts_folder_name);
184c9e2be55Smrg    folderList = (Toc *) XtMalloc((Cardinal)numFolders * sizeof(Toc));
185c9e2be55Smrg    for (i=0 ; i<numFolders ; i++) {
186c9e2be55Smrg	toc = folderList[i] = TUMalloc();
187c9e2be55Smrg	toc->foldername = XtNewString(namelist[i]);
188c9e2be55Smrg	free((char *)namelist[i]);
189c9e2be55Smrg    }
190c9e2be55Smrg    if (! (InitialFolder = TocGetNamed(app_resources.initial_folder_name)))
191c9e2be55Smrg	InitialFolder = TocCreate(app_resources.initial_folder_name);
192c9e2be55Smrg
193c9e2be55Smrg    if (! (DraftsFolder = TocGetNamed(app_resources.drafts_folder_name)))
194c9e2be55Smrg	DraftsFolder = TocCreate(app_resources.drafts_folder_name);
195c9e2be55Smrg    free((char *)namelist);
196c9e2be55Smrg    LoadCheckFiles();
197c9e2be55Smrg}
198c9e2be55Smrg
199c9e2be55Smrg
200c9e2be55Smrg
201c9e2be55Smrg/* Create a toc and add a folder to the folderList.  */
202c9e2be55Smrg
203c9e2be55SmrgToc TocCreate(char *foldername)
204c9e2be55Smrg{
205c9e2be55Smrg    Toc		toc = TUMalloc();
206c9e2be55Smrg
207c9e2be55Smrg    toc->foldername = XtNewString(foldername);
208c9e2be55Smrg    folderList = (Toc *) XtRealloc((char *) folderList,
209c9e2be55Smrg				   (unsigned) ++numFolders * sizeof(Toc));
210c9e2be55Smrg    folderList[numFolders - 1] = toc;
211c9e2be55Smrg    return toc;
212c9e2be55Smrg}
213c9e2be55Smrg
214c9e2be55Smrg
215c9e2be55Smrg/* Create a new folder with the given name. */
216c9e2be55Smrg
217c9e2be55SmrgToc TocCreateFolder(char *foldername)
218c9e2be55Smrg{
219c9e2be55Smrg    Toc toc;
220c9e2be55Smrg    char str[500];
221c9e2be55Smrg    if (TocGetNamed(foldername)) return NULL;
222c9e2be55Smrg    (void) sprintf(str, "%s/%s", app_resources.mail_path, foldername);
223c9e2be55Smrg    if (mkdir(str, 0700) < 0) return NULL;
224c9e2be55Smrg    toc = TocCreate(foldername);
225c9e2be55Smrg    return toc;
226c9e2be55Smrg}
227c9e2be55Smrg
228c9e2be55Smrgint TocHasMail(Toc toc)
229c9e2be55Smrg{
230c9e2be55Smrg    return toc->mailpending;
231c9e2be55Smrg}
232c9e2be55Smrg
233c9e2be55Smrgstatic int CheckForNewMail(Toc toc)
234c9e2be55Smrg{
235c9e2be55Smrg    if (toc->incfile)
236c9e2be55Smrg	return (GetFileLength(toc->incfile) > 0);
237c9e2be55Smrg    else if (toc == InitialFolder) {
238c9e2be55Smrg	char **argv;
239c9e2be55Smrg	char *result;
240c9e2be55Smrg	int hasmail;
241c9e2be55Smrg
242c9e2be55Smrg	argv = MakeArgv(4);
243c9e2be55Smrg	argv[0] = "msgchk";
244c9e2be55Smrg	argv[1] = "-nonotify";
245c9e2be55Smrg	argv[2] = "nomail";
246c9e2be55Smrg	argv[3] = "-nodate";
247c9e2be55Smrg	result = DoCommandToString(argv);
248c9e2be55Smrg	hasmail = (*result != '\0');
249c9e2be55Smrg	XtFree(result);
250c9e2be55Smrg	XtFree((char*)argv);
251c9e2be55Smrg	return hasmail;
252c9e2be55Smrg    }
253c9e2be55Smrg    return False;
254c9e2be55Smrg}
255c9e2be55Smrg
256c9e2be55Smrg/*ARGSUSED*/
257c9e2be55Smrgvoid TocCheckForNewMail(
258c9e2be55Smrg    Boolean update)	/* if True, actually make the check */
259c9e2be55Smrg{
260c9e2be55Smrg    Toc toc;
261c9e2be55Smrg    Scrn scrn;
262c9e2be55Smrg    int i, j, hasmail;
263c9e2be55Smrg    Boolean mail_waiting = False;
264c9e2be55Smrg
265c9e2be55Smrg    if (update) {
266c9e2be55Smrg	for (i=0 ; i<numFolders ; i++) {
267c9e2be55Smrg	    toc = folderList[i];
268c9e2be55Smrg	    if (TocCanIncorporate(toc)) {
269c9e2be55Smrg		toc->mailpending = hasmail = CheckForNewMail(toc);
270c9e2be55Smrg		if (hasmail) mail_waiting = True;
271c9e2be55Smrg		for (j=0 ; j<numScrns ; j++) {
272c9e2be55Smrg		    scrn = scrnList[j];
273c9e2be55Smrg		    if (scrn->kind == STtocAndView)
274c9e2be55Smrg			/* give visual indication of new mail waiting */
275c9e2be55Smrg			BBoxMailFlag(scrn->folderbuttons, TocName(toc),
276c9e2be55Smrg				     hasmail);
277c9e2be55Smrg		}
278c9e2be55Smrg	    }
279c9e2be55Smrg	}
280c9e2be55Smrg    } else {
281c9e2be55Smrg	for (i=0; i < numFolders; i++) {
282c9e2be55Smrg	    toc = folderList[i];
283c9e2be55Smrg	    if (toc->mailpending) {
284c9e2be55Smrg		mail_waiting = True;
285c9e2be55Smrg		break;
286c9e2be55Smrg	    }
287c9e2be55Smrg	}
288c9e2be55Smrg    }
289c9e2be55Smrg
290c9e2be55Smrg    if (app_resources.mail_waiting_flag) {
291c9e2be55Smrg	Arg args[1];
292c9e2be55Smrg	static Boolean icon_state = -1;
293c9e2be55Smrg
294c9e2be55Smrg	if (icon_state != mail_waiting) {
295c9e2be55Smrg	    icon_state = mail_waiting;
296c9e2be55Smrg	    for (i=0; i < numScrns; i++) {
297c9e2be55Smrg		scrn = scrnList[i];
298c9e2be55Smrg		if (scrn->kind == STtocAndView) {
299c9e2be55Smrg		    XtSetArg(args[0], XtNiconPixmap,
300c9e2be55Smrg			     (mail_waiting ? app_resources.new_mail_icon
301c9e2be55Smrg			                   : app_resources.no_mail_icon));
302c9e2be55Smrg		    XtSetValues(scrn->parent, args, (Cardinal)1);
303c9e2be55Smrg		}
304c9e2be55Smrg	    }
305c9e2be55Smrg	}
306c9e2be55Smrg    }
307c9e2be55Smrg}
308c9e2be55Smrg
309c9e2be55Smrg/* Intended to support mutual exclusion on deleting folders, so that you
310c9e2be55Smrg * cannot have two confirm popups at the same time on the same folder.
311c9e2be55Smrg *
312c9e2be55Smrg * You can have confirm popups on different folders simultaneously.
313c9e2be55Smrg * However, I did not protect the user from popping up a delete confirm
314c9e2be55Smrg * popup on folder A, then popping up a delete confirm popup on folder
315d859ff80Smrg * A/subA, then deleting A, then deleting A/subA -- which of course is
316c9e2be55Smrg * already gone, and will cause xmh to Punt.
317c9e2be55Smrg *
318c9e2be55Smrg * TocClearDeletePending is a callback from the No confirmation button
319c9e2be55Smrg * of the confirm popup.
320c9e2be55Smrg */
321c9e2be55Smrg
322c9e2be55SmrgBoolean TocTestAndSetDeletePending(Toc toc)
323c9e2be55Smrg{
324c9e2be55Smrg    Boolean flag;
325c9e2be55Smrg
326c9e2be55Smrg    flag = toc->delete_pending;
327c9e2be55Smrg    toc->delete_pending = True;
328c9e2be55Smrg    return flag;
329c9e2be55Smrg}
330c9e2be55Smrg
331c9e2be55Smrgvoid TocClearDeletePending(Toc toc)
332c9e2be55Smrg{
333c9e2be55Smrg    toc->delete_pending = False;
334c9e2be55Smrg}
335c9e2be55Smrg
336c9e2be55Smrg
337c9e2be55Smrg/* Recursively delete an entire directory.  Nasty. */
338c9e2be55Smrg
339c9e2be55Smrgstatic void NukeDirectory(char *path)
340c9e2be55Smrg{
341c9e2be55Smrg    struct stat buf;
342c9e2be55Smrg
343c9e2be55Smrg#ifdef S_IFLNK
344c9e2be55Smrg    /* POSIX.1 does not discuss symbolic links. */
345c9e2be55Smrg    if (lstat(path, &buf) /* failed */)
346c9e2be55Smrg	return;
347c9e2be55Smrg    if ((buf.st_mode & S_IFMT) == S_IFLNK) {
348c9e2be55Smrg	(void) unlink(path);
349c9e2be55Smrg	return;
350c9e2be55Smrg    }
351c9e2be55Smrg#endif
352c9e2be55Smrg    if (stat(path, &buf) /* failed */)
353c9e2be55Smrg	return;
354c9e2be55Smrg    if (buf.st_mode & S_IWRITE) {
355c9e2be55Smrg	char **argv = MakeArgv(3);
356c9e2be55Smrg	argv[0] = "/bin/rm";
357c9e2be55Smrg	argv[1] = "-rf";
358c9e2be55Smrg	argv[2] = path;
359c9e2be55Smrg	(void) DoCommand(argv, (char*)NULL, (char*)NULL);
360c9e2be55Smrg	XtFree((char*)argv);
361d859ff80Smrg    }
362c9e2be55Smrg}
363c9e2be55Smrg
364c9e2be55Smrg
365c9e2be55Smrg/* Destroy the given folder. */
366c9e2be55Smrg
367c9e2be55Smrgvoid TocDeleteFolder(Toc toc)
368c9e2be55Smrg{
369c9e2be55Smrg    Toc toc2;
370c9e2be55Smrg    int i, j, w;
371c9e2be55Smrg    if (toc == NULL) return;
372c9e2be55Smrg    TUGetFullFolderInfo(toc);
373c9e2be55Smrg
374c9e2be55Smrg    w = -1;
375c9e2be55Smrg    for (i=0 ; i<numFolders ; i++) {
376c9e2be55Smrg	toc2 = folderList[i];
377c9e2be55Smrg	if (toc2 == toc)
378c9e2be55Smrg	    w = i;
379c9e2be55Smrg	else if (toc2->validity == valid)
380c9e2be55Smrg	    for (j=0 ; j<toc2->nummsgs ; j++)
381c9e2be55Smrg		if (toc2->msgs[j]->desttoc == toc)
382c9e2be55Smrg		    MsgSetFate(toc2->msgs[j], Fignore, (Toc) NULL);
383c9e2be55Smrg    }
384c9e2be55Smrg    if (w < 0) Punt("Couldn't find it in TocDeleteFolder!");
385c9e2be55Smrg    NukeDirectory(toc->path);
386c9e2be55Smrg    if (toc->validity == valid) {
387c9e2be55Smrg	for (i=0 ; i<toc->nummsgs ; i++) {
388c9e2be55Smrg	    MsgSetScrnForce(toc->msgs[i], (Scrn) NULL);
389c9e2be55Smrg	    MsgFree(toc->msgs[i]);
390c9e2be55Smrg	}
391c9e2be55Smrg	XtFree((char *) toc->msgs);
392c9e2be55Smrg    }
393c9e2be55Smrg    XtFree((char *)toc);
394c9e2be55Smrg    numFolders--;
395c9e2be55Smrg    for (i=w ; i<numFolders ; i++) folderList[i] = folderList[i+1];
396c9e2be55Smrg}
397c9e2be55Smrg
398c9e2be55Smrg
399c9e2be55Smrg/*
400c9e2be55Smrg * Display the given toc in the given scrn.  If scrn is NULL, then remove the
401c9e2be55Smrg * toc from all scrns displaying it.
402c9e2be55Smrg */
403c9e2be55Smrg
404c9e2be55Smrgvoid TocSetScrn(Toc toc, Scrn scrn)
405c9e2be55Smrg{
406c9e2be55Smrg    Cardinal i;
407c9e2be55Smrg
408c9e2be55Smrg    if (toc == NULL && scrn == NULL) return;
409c9e2be55Smrg    if (scrn == NULL) {
410c9e2be55Smrg	for (i=0 ; i<toc->num_scrns ; i++)
411c9e2be55Smrg	    TocSetScrn((Toc) NULL, toc->scrn[i]);
412c9e2be55Smrg	return;
413c9e2be55Smrg    }
414c9e2be55Smrg    if (scrn->toc == toc) return;
415c9e2be55Smrg    if (scrn->toc != NULL) {
416c9e2be55Smrg	for (i=0 ; i<scrn->toc->num_scrns ; i++)
417c9e2be55Smrg	    if (scrn->toc->scrn[i] == scrn) break;
418c9e2be55Smrg	if (i >= scrn->toc->num_scrns)
419c9e2be55Smrg	    Punt("Couldn't find scrn in TocSetScrn!");
420c9e2be55Smrg	scrn->toc->scrn[i] = scrn->toc->scrn[--scrn->toc->num_scrns];
421c9e2be55Smrg    }
422c9e2be55Smrg    scrn->toc = toc;
423c9e2be55Smrg    if (toc == NULL) {
424c9e2be55Smrg	TUResetTocLabel(scrn);
425c9e2be55Smrg	TURedisplayToc(scrn);
426c9e2be55Smrg	StoreWindowName(scrn, progName);
427c9e2be55Smrg    } else {
428c9e2be55Smrg	toc->num_scrns++;
429c9e2be55Smrg	toc->scrn = (Scrn *) XtRealloc((char *) toc->scrn,
430c9e2be55Smrg				       (unsigned)toc->num_scrns*sizeof(Scrn));
431c9e2be55Smrg	toc->scrn[toc->num_scrns - 1] = scrn;
432c9e2be55Smrg	TUEnsureScanIsValidAndOpen(toc, True);
433c9e2be55Smrg	TUResetTocLabel(scrn);
434c9e2be55Smrg	if (app_resources.prefix_wm_and_icon_name) {
435c9e2be55Smrg	    char wm_name[64];
436c9e2be55Smrg	    int length = strlen(progName);
437c9e2be55Smrg	    (void) strncpy(wm_name, progName, length);
438c9e2be55Smrg	    (void) strncpy(wm_name + length , ": ", 2);
439c9e2be55Smrg	    (void) strcpy(wm_name + length + 2, toc->foldername);
440c9e2be55Smrg	    StoreWindowName(scrn, wm_name);
441c9e2be55Smrg	}
442c9e2be55Smrg	else
443c9e2be55Smrg	    StoreWindowName(scrn, toc->foldername);
444c9e2be55Smrg	TURedisplayToc(scrn);
445c9e2be55Smrg	SetCurrentFolderName(scrn, toc->foldername);
446c9e2be55Smrg    }
447c9e2be55Smrg    EnableProperButtons(scrn);
448c9e2be55Smrg}
449c9e2be55Smrg
450c9e2be55Smrg
451c9e2be55Smrg
452c9e2be55Smrg/* Remove the given message from the toc.  Doesn't actually touch the file.
453c9e2be55Smrg   Also note that it does not free the storage for the msg. */
454c9e2be55Smrg
455c9e2be55Smrgvoid TocRemoveMsg(Toc toc, Msg msg)
456c9e2be55Smrg{
457c9e2be55Smrg    Msg newcurmsg;
458c9e2be55Smrg    MsgList mlist;
459c9e2be55Smrg    int i;
460c9e2be55Smrg    if (toc->validity == unknown)
461c9e2be55Smrg	TUGetFullFolderInfo(toc);
462c9e2be55Smrg    if (toc->validity != valid)
463c9e2be55Smrg	return;
464c9e2be55Smrg    newcurmsg = TocMsgAfter(toc, msg);
465c9e2be55Smrg    if (newcurmsg) newcurmsg->changed = TRUE;
466c9e2be55Smrg    newcurmsg = toc->curmsg;
467c9e2be55Smrg    if (msg == toc->curmsg) {
468c9e2be55Smrg	newcurmsg = TocMsgAfter(toc, msg);
469c9e2be55Smrg	if (newcurmsg == NULL) newcurmsg = TocMsgBefore(toc, msg);
470c9e2be55Smrg	toc->curmsg = NULL;
471c9e2be55Smrg    }
472c9e2be55Smrg    toc->length -= msg->length;
473c9e2be55Smrg    if (msg->visible) toc->lastPos -= msg->length;
474c9e2be55Smrg    for(i = TUGetMsgPosition(toc, msg), toc->nummsgs--; i<toc->nummsgs ; i++) {
475c9e2be55Smrg	toc->msgs[i] = toc->msgs[i+1];
476c9e2be55Smrg	if (msg->visible) toc->msgs[i]->position -= msg->length;
477c9e2be55Smrg    }
478c9e2be55Smrg    for (i=0 ; i<toc->numsequences ; i++) {
479c9e2be55Smrg	mlist = toc->seqlist[i]->mlist;
480c9e2be55Smrg	if (mlist) DeleteMsgFromMsgList(mlist, msg);
481c9e2be55Smrg    }
482c9e2be55Smrg
483c9e2be55Smrg    if (msg->visible && toc->num_scrns > 0 && !toc->needsrepaint)
484c9e2be55Smrg	TSourceInvalid(toc, msg->position, -msg->length);
485c9e2be55Smrg    TocSetCurMsg(toc, newcurmsg);
486c9e2be55Smrg    TUSaveTocFile(toc);
487c9e2be55Smrg}
488d859ff80Smrg
489c9e2be55Smrg
490c9e2be55Smrg
491c9e2be55Smrgvoid TocRecheckValidity(Toc toc)
492c9e2be55Smrg{
493c9e2be55Smrg    Cardinal i;
494c9e2be55Smrg
495c9e2be55Smrg    if (toc && toc->validity == valid && TUScanFileOutOfDate(toc)) {
496c9e2be55Smrg	if (app_resources.block_events_on_busy) ShowBusyCursor();
497c9e2be55Smrg
498c9e2be55Smrg	TUScanFileForToc(toc);
499c9e2be55Smrg	if (toc->source)
500c9e2be55Smrg	    TULoadTocFile(toc);
501c9e2be55Smrg	for (i=0 ; i<toc->num_scrns ; i++)
502c9e2be55Smrg	    TURedisplayToc(toc->scrn[i]);
503c9e2be55Smrg
504c9e2be55Smrg	if (app_resources.block_events_on_busy) UnshowBusyCursor();
505c9e2be55Smrg    }
506c9e2be55Smrg}
507c9e2be55Smrg
508c9e2be55Smrg
509c9e2be55Smrg/* Set the current message. */
510c9e2be55Smrg
511c9e2be55Smrgvoid TocSetCurMsg(Toc toc, Msg msg)
512c9e2be55Smrg{
513c9e2be55Smrg    Msg msg2;
514c9e2be55Smrg    Cardinal i;
515c9e2be55Smrg
516c9e2be55Smrg    if (toc->validity != valid) return;
517c9e2be55Smrg    if (msg != toc->curmsg) {
518c9e2be55Smrg	msg2 = toc->curmsg;
519c9e2be55Smrg	toc->curmsg = msg;
520c9e2be55Smrg	if (msg2)
521c9e2be55Smrg	    MsgSetFate(msg2, msg2->fate, msg2->desttoc);
522c9e2be55Smrg    }
523c9e2be55Smrg    if (msg) {
524c9e2be55Smrg	MsgSetFate(msg, msg->fate, msg->desttoc);
525c9e2be55Smrg	if (toc->num_scrns) {
526c9e2be55Smrg	    if (toc->stopupdate)
527c9e2be55Smrg		toc->needsrepaint = TRUE;
528c9e2be55Smrg	    else {
529c9e2be55Smrg		for (i=0 ; i<toc->num_scrns ; i++)
530c9e2be55Smrg		    XawTextSetInsertionPoint(toc->scrn[i]->tocwidget,
531c9e2be55Smrg						msg->position);
532c9e2be55Smrg	    }
533c9e2be55Smrg	}
534c9e2be55Smrg    }
535c9e2be55Smrg}
536c9e2be55Smrg
537c9e2be55Smrg
538c9e2be55Smrg/* Return the current message. */
539c9e2be55Smrg
540c9e2be55SmrgMsg TocGetCurMsg(Toc toc)
541c9e2be55Smrg{
542c9e2be55Smrg    return toc->curmsg;
543c9e2be55Smrg}
544c9e2be55Smrg
545c9e2be55Smrg
546c9e2be55Smrg
547c9e2be55Smrg
548c9e2be55Smrg/* Return the message after the given one.  (If none, return NULL.) */
549c9e2be55Smrg
550c9e2be55SmrgMsg TocMsgAfter(Toc toc, Msg msg)
551c9e2be55Smrg{
552c9e2be55Smrg    int i;
553c9e2be55Smrg    i = TUGetMsgPosition(toc, msg);
554c9e2be55Smrg    do {
555c9e2be55Smrg	i++;
556c9e2be55Smrg	if (i >= toc->nummsgs)
557c9e2be55Smrg	    return NULL;
558c9e2be55Smrg    } while (!(toc->msgs[i]->visible));
559c9e2be55Smrg    return toc->msgs[i];
560c9e2be55Smrg}
561c9e2be55Smrg
562c9e2be55Smrg
563c9e2be55Smrg
564c9e2be55Smrg/* Return the message before the given one.  (If none, return NULL.) */
565c9e2be55Smrg
566c9e2be55SmrgMsg TocMsgBefore(Toc toc, Msg msg)
567c9e2be55Smrg{
568c9e2be55Smrg    int i;
569c9e2be55Smrg    i = TUGetMsgPosition(toc, msg);
570c9e2be55Smrg    do {
571c9e2be55Smrg	i--;
572c9e2be55Smrg	if (i < 0)
573c9e2be55Smrg	    return NULL;
574c9e2be55Smrg    } while (!(toc->msgs[i]->visible));
575c9e2be55Smrg    return toc->msgs[i];
576c9e2be55Smrg}
577c9e2be55Smrg
578c9e2be55Smrg
579c9e2be55Smrg
580c9e2be55Smrg/* The caller KNOWS the toc's information is out of date; rescan it. */
581c9e2be55Smrg
582c9e2be55Smrgvoid TocForceRescan(Toc toc)
583c9e2be55Smrg{
584c9e2be55Smrg    register Cardinal i;
585c9e2be55Smrg
586c9e2be55Smrg    if (toc->num_scrns) {
587c9e2be55Smrg	toc->viewedseq = toc->seqlist[0];
588c9e2be55Smrg	for (i=0 ; i<toc->num_scrns ; i++)
589c9e2be55Smrg	    TUResetTocLabel(toc->scrn[i]);
590c9e2be55Smrg	TUScanFileForToc(toc);
591c9e2be55Smrg	TULoadTocFile(toc);
592c9e2be55Smrg	for (i=0 ; i<toc->num_scrns ; i++)
593c9e2be55Smrg	    TURedisplayToc(toc->scrn[i]);
594c9e2be55Smrg    } else {
595c9e2be55Smrg	TUGetFullFolderInfo(toc);
596c9e2be55Smrg	(void) unlink(toc->scanfile);
597c9e2be55Smrg	toc->validity = invalid;
598c9e2be55Smrg    }
599c9e2be55Smrg}
600c9e2be55Smrg
601c9e2be55Smrg
602c9e2be55Smrg
603c9e2be55Smrg/* The caller has just changed a sequence list.  Reread them from mh. */
604c9e2be55Smrg
605c9e2be55Smrgvoid TocReloadSeqLists(Toc toc)
606c9e2be55Smrg{
607c9e2be55Smrg    Cardinal i;
608c9e2be55Smrg
609c9e2be55Smrg    TocSetCacheValid(toc);
610c9e2be55Smrg    TULoadSeqLists(toc);
611c9e2be55Smrg    TURefigureWhatsVisible(toc);
612c9e2be55Smrg    for (i=0 ; i<toc->num_scrns ; i++) {
613c9e2be55Smrg	TUResetTocLabel(toc->scrn[i]);
614c9e2be55Smrg	EnableProperButtons(toc->scrn[i]);
615c9e2be55Smrg    }
616c9e2be55Smrg}
617c9e2be55Smrg
618c9e2be55Smrg
619c9e2be55Smrg/*ARGSUSED*/
620c9e2be55Smrgvoid XmhReloadSeqLists(
621c9e2be55Smrg    Widget	w,
622c9e2be55Smrg    XEvent	*event,
623c9e2be55Smrg    String	*params,
624c9e2be55Smrg    Cardinal	*num_params)
625c9e2be55Smrg{
626c9e2be55Smrg    Scrn scrn = ScrnFromWidget(w);
627c9e2be55Smrg    TocReloadSeqLists(scrn->toc);
628c9e2be55Smrg    TUCheckSequenceMenu(scrn->toc);
629c9e2be55Smrg}
630c9e2be55Smrg
631c9e2be55Smrg
632c9e2be55Smrg
633c9e2be55Smrg/* Return TRUE if the toc has an interesting sequence. */
634c9e2be55Smrg
635c9e2be55Smrgint TocHasSequences(Toc toc)
636c9e2be55Smrg{
637c9e2be55Smrg    return toc && toc->numsequences > 1;
638c9e2be55Smrg}
639c9e2be55Smrg
640c9e2be55Smrg
641c9e2be55Smrg/* Change which sequence is being viewed. */
642c9e2be55Smrg
643c9e2be55Smrgvoid TocChangeViewedSeq(Toc toc, Sequence seq)
644c9e2be55Smrg{
645c9e2be55Smrg    if (seq == NULL) seq = toc->viewedseq;
646c9e2be55Smrg    toc->viewedseq = seq;
647c9e2be55Smrg    toc->force_reset = True; /* %%% force Text source to be reset */
648c9e2be55Smrg    TURefigureWhatsVisible(toc);
649c9e2be55Smrg}
650c9e2be55Smrg
651c9e2be55Smrg
652c9e2be55Smrg/* Return the sequence with the given name in the given toc. */
653c9e2be55Smrg
654c9e2be55SmrgSequence TocGetSeqNamed(Toc toc, char *name)
655c9e2be55Smrg{
656c9e2be55Smrg    register int i;
657c9e2be55Smrg    if (name == NULL)
658c9e2be55Smrg	return (Sequence) NULL;
659c9e2be55Smrg
660c9e2be55Smrg    for (i=0 ; i<toc->numsequences ; i++)
661c9e2be55Smrg	if (strcmp(toc->seqlist[i]->name, name) == 0)
662c9e2be55Smrg	    return toc->seqlist[i];
663c9e2be55Smrg    return (Sequence) NULL;
664c9e2be55Smrg}
665c9e2be55Smrg
666c9e2be55Smrg
667c9e2be55Smrg/* Return the sequence currently being viewed in the toc. */
668c9e2be55Smrg
669c9e2be55SmrgSequence TocViewedSequence(Toc toc)
670c9e2be55Smrg{
671c9e2be55Smrg    return toc->viewedseq;
672c9e2be55Smrg}
673c9e2be55Smrg
674c9e2be55Smrg
675c9e2be55Smrg/* Set the selected sequence in the toc */
676c9e2be55Smrg
677c9e2be55Smrgvoid TocSetSelectedSequence(
678c9e2be55Smrg    Toc		toc,
679c9e2be55Smrg    Sequence	sequence)
680c9e2be55Smrg{
681d859ff80Smrg    if (toc)
682c9e2be55Smrg	toc->selectseq = sequence;
683c9e2be55Smrg}
684c9e2be55Smrg
685c9e2be55Smrg
686c9e2be55Smrg/* Return the sequence currently selected */
687c9e2be55Smrg
688c9e2be55SmrgSequence TocSelectedSequence(Toc toc)
689c9e2be55Smrg{
690c9e2be55Smrg    if (toc) return (toc->selectseq);
691c9e2be55Smrg    else return (Sequence) NULL;
692c9e2be55Smrg}
693c9e2be55Smrg
694c9e2be55Smrg
695c9e2be55Smrg/* Return the list of messages currently selected. */
696c9e2be55Smrg
697c9e2be55Smrg#define SrcScan XawTextSourceScan
698c9e2be55Smrg
699c9e2be55SmrgMsgList TocCurMsgList(Toc toc)
700c9e2be55Smrg{
701c9e2be55Smrg    MsgList result;
702c9e2be55Smrg    XawTextPosition pos1, pos2;
703c9e2be55Smrg
704c9e2be55Smrg    if (toc->num_scrns == 0) return NULL;
705c9e2be55Smrg    result = MakeNullMsgList();
706c9e2be55Smrg    XawTextGetSelectionPos( toc->scrn[0]->tocwidget, &pos1, &pos2); /* %%% */
707c9e2be55Smrg    if (pos1 < pos2) {
708c9e2be55Smrg	pos1 = SrcScan(toc->source, pos1, XawstEOL, XawsdLeft, 1, FALSE);
709c9e2be55Smrg	pos2 = SrcScan(toc->source, pos2, XawstPositions, XawsdLeft, 1, TRUE);
710c9e2be55Smrg	pos2 = SrcScan(toc->source, pos2, XawstEOL, XawsdRight, 1, FALSE);
711c9e2be55Smrg	while (pos1 < pos2) {
712c9e2be55Smrg	    AppendMsgList(result, MsgFromPosition(toc, pos1, XawsdRight));
713c9e2be55Smrg	    pos1 = SrcScan(toc->source, pos1, XawstEOL, XawsdRight, 1, TRUE);
714c9e2be55Smrg	}
715c9e2be55Smrg    }
716c9e2be55Smrg    return result;
717c9e2be55Smrg}
718c9e2be55Smrg
719c9e2be55Smrg
720c9e2be55Smrg
721c9e2be55Smrg/* Unset the current selection. */
722c9e2be55Smrg
723c9e2be55Smrgvoid TocUnsetSelection(Toc toc)
724c9e2be55Smrg{
725c9e2be55Smrg    if (toc->source)
726c9e2be55Smrg        XawTextUnsetSelection(toc->scrn[0]->tocwidget);
727c9e2be55Smrg}
728c9e2be55Smrg
729c9e2be55Smrg
730c9e2be55Smrg
731c9e2be55Smrg/* Create a brand new, blank message. */
732c9e2be55Smrg
733c9e2be55SmrgMsg TocMakeNewMsg(Toc toc)
734c9e2be55Smrg{
735c9e2be55Smrg    Msg msg;
736c9e2be55Smrg    static int looping = False;
737c9e2be55Smrg    TUEnsureScanIsValidAndOpen(toc, False);
738c9e2be55Smrg    msg = TUAppendToc(toc, "####  empty\n");
739c9e2be55Smrg    if (FileExists(MsgFileName(msg))) {
740c9e2be55Smrg	if (looping++) Punt( "Cannot correct scan file" );
741c9e2be55Smrg        DEBUG2("**** FOLDER %s WAS INVALID; msg %d already existed!\n",
742c9e2be55Smrg	       toc->foldername, msg->msgid);
743c9e2be55Smrg	TocForceRescan(toc);
744c9e2be55Smrg	return TocMakeNewMsg(toc); /* Try again.  Using recursion here is ugly,
745c9e2be55Smrg				      but what the hack ... */
746c9e2be55Smrg    }
747c9e2be55Smrg    CopyFileAndCheck("/dev/null", MsgFileName(msg));
748c9e2be55Smrg    looping = False;
749c9e2be55Smrg    return msg;
750c9e2be55Smrg}
751c9e2be55Smrg
752c9e2be55Smrg
753c9e2be55Smrg/* Set things to not update cache or display until further notice. */
754c9e2be55Smrg
755c9e2be55Smrgvoid TocStopUpdate(Toc toc)
756c9e2be55Smrg{
757c9e2be55Smrg    Cardinal i;
758c9e2be55Smrg
759c9e2be55Smrg    for (i=0 ; i<toc->num_scrns ; i++)
760c9e2be55Smrg	XawTextDisableRedisplay(toc->scrn[i]->tocwidget);
761c9e2be55Smrg    toc->stopupdate++;
762c9e2be55Smrg}
763c9e2be55Smrg
764c9e2be55Smrg
765c9e2be55Smrg/* Start updating again, and do whatever updating has been queued. */
766c9e2be55Smrg
767c9e2be55Smrgvoid TocStartUpdate(Toc toc)
768c9e2be55Smrg{
769c9e2be55Smrg    Cardinal i;
770c9e2be55Smrg
771c9e2be55Smrg    if (toc->stopupdate && --(toc->stopupdate) == 0) {
772c9e2be55Smrg	for (i=0 ; i<toc->num_scrns ; i++) {
773d859ff80Smrg	    if (toc->needsrepaint)
774c9e2be55Smrg		TURedisplayToc(toc->scrn[i]);
775c9e2be55Smrg	    if (toc->needslabelupdate)
776c9e2be55Smrg		TUResetTocLabel(toc->scrn[i]);
777c9e2be55Smrg	}
778c9e2be55Smrg	if (toc->needscachesave)
779c9e2be55Smrg	    TUSaveTocFile(toc);
780c9e2be55Smrg    }
781c9e2be55Smrg    for (i=0 ; i<toc->num_scrns ; i++)
782c9e2be55Smrg	XawTextEnableRedisplay(toc->scrn[i]->tocwidget);
783c9e2be55Smrg}
784c9e2be55Smrg
785c9e2be55Smrg
786c9e2be55Smrg
787c9e2be55Smrg/* Something has happened that could later convince us that our cache is out
788c9e2be55Smrg   of date.  Make this not happen; our cache really *is* up-to-date. */
789c9e2be55Smrg
790c9e2be55Smrgvoid TocSetCacheValid(Toc toc)
791c9e2be55Smrg{
792c9e2be55Smrg    TUSaveTocFile(toc);
793c9e2be55Smrg}
794c9e2be55Smrg
795c9e2be55Smrg
796c9e2be55Smrg/* Return the full folder pathname of the given toc, prefixed w/'+' */
797c9e2be55Smrg
798c9e2be55Smrgchar *TocMakeFolderName(Toc toc)
799c9e2be55Smrg{
800c9e2be55Smrg    char* name = XtMalloc((Cardinal) (strlen(toc->path) + 2) );
801c9e2be55Smrg    (void)sprintf( name, "+%s", toc->path );
802c9e2be55Smrg    return name;
803c9e2be55Smrg}
804c9e2be55Smrg
805c9e2be55Smrgchar *TocName(Toc toc)
806c9e2be55Smrg{
807c9e2be55Smrg    return toc->foldername;
808c9e2be55Smrg}
809c9e2be55Smrg
810c9e2be55Smrg
811c9e2be55Smrg
812c9e2be55Smrg/* Given a foldername, return the corresponding toc. */
813c9e2be55Smrg
814c9e2be55SmrgToc TocGetNamed(char *name)
815c9e2be55Smrg{
816c9e2be55Smrg    int i;
817c9e2be55Smrg    for (i=0; i<numFolders ; i++)
818c9e2be55Smrg	if (strcmp(folderList[i]->foldername, name) == 0) return folderList[i];
819c9e2be55Smrg    return NULL;
820c9e2be55Smrg}
821c9e2be55Smrg
822c9e2be55Smrg
823c9e2be55SmrgBoolean TocHasChanges(Toc toc)
824c9e2be55Smrg{
825c9e2be55Smrg    int i;
826c9e2be55Smrg    for (i=0 ; i<toc->nummsgs ; i++)
827c9e2be55Smrg	if (toc->msgs[i]->fate != Fignore) return True;
828c9e2be55Smrg
829c9e2be55Smrg    return False;
830c9e2be55Smrg}
831c9e2be55Smrg
832c9e2be55Smrg
833c9e2be55Smrg
834c9e2be55Smrg/* Throw out all changes to this toc, and close all views of msgs in it.
835c9e2be55Smrg   Requires confirmation by the user. */
836c9e2be55Smrg
837c9e2be55Smrg/*ARGSUSED*/
838c9e2be55Smrgstatic void TocCataclysmOkay(
839c9e2be55Smrg    Widget	widget,		/* unused */
840c9e2be55Smrg    XtPointer	client_data,
841c9e2be55Smrg    XtPointer	call_data)	/* unused */
842c9e2be55Smrg{
843c9e2be55Smrg    Toc			toc = (Toc) client_data;
844c9e2be55Smrg    register int	i;
845c9e2be55Smrg
846c9e2be55Smrg    for (i=0; i < toc->nummsgs; i++)
847c9e2be55Smrg	MsgSetFate(toc->msgs[i], Fignore, (Toc)NULL);
848c9e2be55Smrg
849c9e2be55Smrg/* Doesn't make sense to have this MsgSetScrn for loop here. dmc. %%% */
850c9e2be55Smrg    for (i=0; i < toc->nummsgs; i++)
851d859ff80Smrg	MsgSetScrn(toc->msgs[i], (Scrn) NULL, (XtCallbackList) NULL,
852c9e2be55Smrg		   (XtCallbackList) NULL);
853c9e2be55Smrg}
854d859ff80Smrg
855c9e2be55Smrgint TocConfirmCataclysm(
856c9e2be55Smrg    Toc			toc,
857c9e2be55Smrg    XtCallbackList	confirms,
858c9e2be55Smrg    XtCallbackList	cancels)
859d859ff80Smrg{
860c9e2be55Smrg    register int	i;
861c9e2be55Smrg
862c9e2be55Smrg    static XtCallbackRec yes_callbacks[] = {
863c9e2be55Smrg	{TocCataclysmOkay,	(XtPointer) NULL},
864c9e2be55Smrg	{(XtCallbackProc) NULL,	(XtPointer) NULL},
865c9e2be55Smrg	{(XtCallbackProc) NULL,	(XtPointer) NULL}
866c9e2be55Smrg    };
867c9e2be55Smrg
868c9e2be55Smrg    if (! toc)
869c9e2be55Smrg	return 0;
870c9e2be55Smrg
871c9e2be55Smrg    if (TocHasChanges(toc)) {
872c9e2be55Smrg	char		str[300];
873c9e2be55Smrg	Widget		tocwidget;
874c9e2be55Smrg
875c9e2be55Smrg	(void)sprintf(str,"Are you sure you want to remove all changes to %s?",
876c9e2be55Smrg		      toc->foldername);
877c9e2be55Smrg	yes_callbacks[0].closure = (XtPointer) toc;
878c9e2be55Smrg	yes_callbacks[1].callback = confirms[0].callback;
879c9e2be55Smrg	yes_callbacks[1].closure = confirms[0].closure;
880c9e2be55Smrg
881c9e2be55Smrg	tocwidget = NULL;
882c9e2be55Smrg	for (i=0; i < toc->num_scrns; i++)
883c9e2be55Smrg	    if (toc->scrn[i]->mapped) {
884c9e2be55Smrg		tocwidget = toc->scrn[i]->tocwidget;
885c9e2be55Smrg		break;
886c9e2be55Smrg	    }
887c9e2be55Smrg
888c9e2be55Smrg	PopupConfirm(tocwidget, str, yes_callbacks, cancels);
889c9e2be55Smrg	return NEEDS_CONFIRMATION;
890c9e2be55Smrg    }
891c9e2be55Smrg    else {
892c9e2be55Smrg/* Doesn't make sense to have this MsgSetFate for loop here. dmc. %%% */
893c9e2be55Smrg	for (i=0 ; i<toc->nummsgs ; i++)
894c9e2be55Smrg	    MsgSetFate(toc->msgs[i], Fignore, (Toc)NULL);
895c9e2be55Smrg
896c9e2be55Smrg	for (i=0 ; i<toc->nummsgs ; i++)
897c9e2be55Smrg	    if (MsgSetScrn(toc->msgs[i], (Scrn) NULL, confirms, cancels))
898c9e2be55Smrg		return NEEDS_CONFIRMATION;
899c9e2be55Smrg	return 0;
900c9e2be55Smrg    }
901c9e2be55Smrg}
902d859ff80Smrg
903c9e2be55Smrg
904c9e2be55Smrg/* Commit all the changes in this toc; all messages will meet their 'fate'. */
905c9e2be55Smrg
906c9e2be55Smrg/*ARGSUSED*/
907c9e2be55Smrgvoid TocCommitChanges(
908c9e2be55Smrg    Widget	widget,		/* unused */
909d859ff80Smrg    XtPointer	client_data,
910c9e2be55Smrg    XtPointer	call_data)	/* unused */
911c9e2be55Smrg{
912c9e2be55Smrg    Toc toc = (Toc) client_data;
913c9e2be55Smrg    Msg msg;
914c9e2be55Smrg    int i, cur = 0;
915c9e2be55Smrg    char str[100], **argv = NULL;
916d859ff80Smrg    FateType curfate, fate;
917c9e2be55Smrg    Toc desttoc;
918c9e2be55Smrg    Toc curdesttoc = NULL;
919c9e2be55Smrg    XtCallbackRec	confirms[2];
920c9e2be55Smrg
921c9e2be55Smrg    confirms[0].callback = TocCommitChanges;
922c9e2be55Smrg    confirms[0].closure = (XtPointer) toc;
923c9e2be55Smrg    confirms[1].callback = (XtCallbackProc) NULL;
924c9e2be55Smrg    confirms[1].closure = (XtPointer) NULL;
925c9e2be55Smrg
926c9e2be55Smrg    if (toc == NULL) return;
927c9e2be55Smrg    for (i=0 ; i<toc->nummsgs ; i++) {
928c9e2be55Smrg	msg = toc->msgs[i];
929c9e2be55Smrg	fate = MsgGetFate(msg, (Toc *)NULL);
930c9e2be55Smrg	if (fate != Fignore && fate != Fcopy)
931c9e2be55Smrg	    if (MsgSetScrn(msg, (Scrn) NULL, confirms, (XtCallbackList) NULL)
932c9e2be55Smrg		== NEEDS_CONFIRMATION)
933c9e2be55Smrg	        return;
934c9e2be55Smrg    }
935c9e2be55Smrg    XFlush(XtDisplay(toc->scrn[0]->parent));
936c9e2be55Smrg    for (i=0 ; i<numFolders ; i++)
937c9e2be55Smrg	TocStopUpdate(folderList[i]);
938c9e2be55Smrg    toc->haschanged = TRUE;
939c9e2be55Smrg    if (app_resources.block_events_on_busy) ShowBusyCursor();
940c9e2be55Smrg
941c9e2be55Smrg    do {
942c9e2be55Smrg	curfate = Fignore;
943c9e2be55Smrg	i = 0;
944c9e2be55Smrg	while (i < toc->nummsgs) {
945c9e2be55Smrg	    msg = toc->msgs[i];
946c9e2be55Smrg	    fate = MsgGetFate(msg, &desttoc);
947c9e2be55Smrg	    if (curfate == Fignore && fate != Fignore) {
948c9e2be55Smrg		curfate = fate;
949c9e2be55Smrg		argv = MakeArgv(2);
950c9e2be55Smrg		switch (curfate) {
951c9e2be55Smrg		  case Fdelete:
952c9e2be55Smrg		    argv[0] = XtNewString("rmm");
953c9e2be55Smrg		    argv[1] = TocMakeFolderName(toc);
954c9e2be55Smrg		    cur = 2;
955c9e2be55Smrg		    curdesttoc = NULL;
956c9e2be55Smrg		    break;
957c9e2be55Smrg		  case Fmove:
958c9e2be55Smrg		  case Fcopy:
959c9e2be55Smrg		    argv[0] = XtNewString("refile");
960c9e2be55Smrg		    cur = 1;
961c9e2be55Smrg		    curdesttoc = desttoc;
962c9e2be55Smrg		    break;
963c9e2be55Smrg		  default:
964c9e2be55Smrg		    break;
965c9e2be55Smrg		}
966c9e2be55Smrg	    }
967c9e2be55Smrg	    if (curfate != Fignore &&
968c9e2be55Smrg		  curfate == fate && desttoc == curdesttoc) {
969c9e2be55Smrg		argv = ResizeArgv(argv, cur + 1);
970c9e2be55Smrg		(void) sprintf(str, "%d", MsgGetId(msg));
971c9e2be55Smrg		argv[cur++] = XtNewString(str);
972c9e2be55Smrg		MsgSetFate(msg, Fignore, (Toc)NULL);
973c9e2be55Smrg		if (curdesttoc) {
974c9e2be55Smrg		    (void) TUAppendToc(curdesttoc, MsgGetScanLine(msg));
975c9e2be55Smrg		    curdesttoc->haschanged = TRUE;
976c9e2be55Smrg		}
977c9e2be55Smrg		if (curfate != Fcopy) {
978c9e2be55Smrg		    TocRemoveMsg(toc, msg);
979c9e2be55Smrg		    MsgFree(msg);
980c9e2be55Smrg		    i--;
981c9e2be55Smrg		}
982c9e2be55Smrg		if (cur > 40)
983c9e2be55Smrg		    break;	/* Do only 40 at a time, just to be safe. */
984d859ff80Smrg	    }
985c9e2be55Smrg	    i++;
986c9e2be55Smrg	}
987c9e2be55Smrg	if (curfate != Fignore) {
988c9e2be55Smrg	    switch (curfate) {
989c9e2be55Smrg	      case Fmove:
990c9e2be55Smrg	      case Fcopy:
991c9e2be55Smrg		argv = ResizeArgv(argv, cur + 4);
992c9e2be55Smrg		argv[cur++] = XtNewString(curfate == Fmove ? "-nolink"
993c9e2be55Smrg				       			   : "-link");
994c9e2be55Smrg		argv[cur++] = XtNewString("-src");
995c9e2be55Smrg		argv[cur++] = TocMakeFolderName(toc);
996c9e2be55Smrg		argv[cur++] = TocMakeFolderName(curdesttoc);
997c9e2be55Smrg		break;
998c9e2be55Smrg	      default:
999c9e2be55Smrg		break;
1000c9e2be55Smrg	    }
1001c9e2be55Smrg	    if (app_resources.debug) {
1002c9e2be55Smrg		for (i = 0; i < cur; i++)
1003c9e2be55Smrg		    (void) fprintf(stderr, "%s ", argv[i]);
1004c9e2be55Smrg		(void) fprintf(stderr, "\n");
1005c9e2be55Smrg		(void) fflush(stderr);
1006c9e2be55Smrg	    }
1007c9e2be55Smrg	    DoCommand(argv, (char *) NULL, (char *) NULL);
1008c9e2be55Smrg	    for (i = 0; argv[i]; i++)
1009c9e2be55Smrg		XtFree((char *) argv[i]);
1010c9e2be55Smrg	    XtFree((char *) argv);
1011c9e2be55Smrg	}
1012c9e2be55Smrg    } while (curfate != Fignore);
1013c9e2be55Smrg    for (i=0 ; i<numFolders ; i++) {
1014c9e2be55Smrg	if (folderList[i]->haschanged) {
1015c9e2be55Smrg	    TocReloadSeqLists(folderList[i]);
1016c9e2be55Smrg	    folderList[i]->haschanged = FALSE;
1017c9e2be55Smrg	}
1018c9e2be55Smrg	TocStartUpdate(folderList[i]);
1019c9e2be55Smrg    }
1020c9e2be55Smrg
1021c9e2be55Smrg    if (app_resources.block_events_on_busy) UnshowBusyCursor();
1022c9e2be55Smrg}
1023c9e2be55Smrg
1024c9e2be55Smrg
1025c9e2be55Smrg
1026c9e2be55Smrg/* Return whether the given toc can incorporate mail. */
1027c9e2be55Smrg
1028c9e2be55Smrgint TocCanIncorporate(Toc toc)
1029c9e2be55Smrg{
1030c9e2be55Smrg    return (toc && (toc == InitialFolder || toc->incfile));
1031c9e2be55Smrg}
1032c9e2be55Smrg
1033c9e2be55Smrg
1034c9e2be55Smrg/* Incorporate new messages into the given toc. */
1035c9e2be55Smrg
1036c9e2be55Smrgint TocIncorporate(Toc toc)
1037c9e2be55Smrg{
1038c9e2be55Smrg    char **argv;
1039c9e2be55Smrg    char str[100], *file, *ptr;
1040c9e2be55Smrg    Msg msg, firstmessage = NULL;
1041c9e2be55Smrg    FILEPTR fid;
1042c9e2be55Smrg
1043c9e2be55Smrg    argv = MakeArgv(toc->incfile ? 7 : 4);
1044c9e2be55Smrg    argv[0] = "inc";
1045c9e2be55Smrg    argv[1] = TocMakeFolderName(toc);
1046c9e2be55Smrg    argv[2] = "-width";
1047c9e2be55Smrg    (void) sprintf(str, "%d", app_resources.toc_width);
1048c9e2be55Smrg    argv[3] = str;
1049c9e2be55Smrg    if (toc->incfile) {
1050c9e2be55Smrg	argv[4] = "-file";
1051c9e2be55Smrg	argv[5] = toc->incfile;
1052c9e2be55Smrg	argv[6] = "-truncate";
1053c9e2be55Smrg    }
1054c9e2be55Smrg    if (app_resources.block_events_on_busy) ShowBusyCursor();
1055c9e2be55Smrg
1056c9e2be55Smrg    file = DoCommandToFile(argv);
1057c9e2be55Smrg    XtFree(argv[1]);
1058c9e2be55Smrg    XtFree((char *)argv);
1059c9e2be55Smrg    TUGetFullFolderInfo(toc);
1060c9e2be55Smrg    if (toc->validity == valid) {
1061c9e2be55Smrg	fid = FOpenAndCheck(file, "r");
1062c9e2be55Smrg	TocStopUpdate(toc);
1063c9e2be55Smrg	while ((ptr = ReadLineWithCR(fid))) {
1064c9e2be55Smrg	    if (atoi(ptr) > 0) {
1065c9e2be55Smrg		msg = TUAppendToc(toc, ptr);
1066c9e2be55Smrg		if (firstmessage == NULL) firstmessage = msg;
1067c9e2be55Smrg	    }
1068c9e2be55Smrg	}
1069c9e2be55Smrg	if (firstmessage && firstmessage->visible) {
1070c9e2be55Smrg	    TocSetCurMsg(toc, firstmessage);
1071c9e2be55Smrg	}
1072c9e2be55Smrg	TocStartUpdate(toc);
1073c9e2be55Smrg	myfclose(fid);
1074c9e2be55Smrg    }
1075c9e2be55Smrg    DeleteFileAndCheck(file);
1076c9e2be55Smrg
1077c9e2be55Smrg    if (app_resources.block_events_on_busy) UnshowBusyCursor();
1078c9e2be55Smrg
1079c9e2be55Smrg    toc->mailpending = False;
1080c9e2be55Smrg    return (firstmessage != NULL);
1081c9e2be55Smrg}
1082c9e2be55Smrg
1083c9e2be55Smrg
1084c9e2be55Smrg/* The given message has changed.  Rescan it and change the scanfile. */
1085c9e2be55Smrg
1086c9e2be55Smrgvoid TocMsgChanged(Toc toc, Msg msg)
1087c9e2be55Smrg{
1088c9e2be55Smrg    char **argv, str[100], str2[10], *ptr;
1089c9e2be55Smrg    int length, delta;
1090c9e2be55Smrg    int i;
1091c9e2be55Smrg    FateType fate;
1092c9e2be55Smrg    Toc desttoc;
1093c9e2be55Smrg
1094c9e2be55Smrg    if (toc->validity != valid) return;
1095c9e2be55Smrg    fate = MsgGetFate(msg, &desttoc);
1096c9e2be55Smrg    MsgSetFate(msg, Fignore, (Toc) NULL);
1097c9e2be55Smrg    argv = MakeArgv(6);
1098c9e2be55Smrg    argv[0] = "scan";
1099c9e2be55Smrg    argv[1] = TocMakeFolderName(toc);
1100c9e2be55Smrg    (void) sprintf(str, "%d", msg->msgid);
1101c9e2be55Smrg    argv[2] = str;
1102c9e2be55Smrg    argv[3] = "-width";
1103c9e2be55Smrg    (void) sprintf(str2, "%d", app_resources.toc_width);
1104c9e2be55Smrg    argv[4] = str2;
1105c9e2be55Smrg    argv[5] = "-noheader";
1106c9e2be55Smrg    ptr = DoCommandToString(argv);
1107c9e2be55Smrg    XtFree(argv[1]);
1108c9e2be55Smrg    XtFree((char *) argv);
1109c9e2be55Smrg    if (strcmp(ptr, msg->buf) != 0) {
1110c9e2be55Smrg	length = strlen(ptr);
1111c9e2be55Smrg	delta = length - msg->length;
1112c9e2be55Smrg	XtFree(msg->buf);
1113c9e2be55Smrg	msg->buf = ptr;
1114c9e2be55Smrg	msg->length = length;
1115c9e2be55Smrg	toc->length += delta;
1116c9e2be55Smrg	if (msg->visible) {
1117c9e2be55Smrg	    if (delta != 0) {
1118c9e2be55Smrg		for (i=TUGetMsgPosition(toc, msg)+1; i<toc->nummsgs ; i++)
1119c9e2be55Smrg		    toc->msgs[i]->position += delta;
1120c9e2be55Smrg		toc->lastPos += delta;
1121c9e2be55Smrg	    }
1122c9e2be55Smrg	    for (i=0 ; i<toc->num_scrns ; i++)
1123c9e2be55Smrg		TURedisplayToc(toc->scrn[i]);
1124c9e2be55Smrg	}
1125c9e2be55Smrg	MsgSetFate(msg, fate, desttoc);
1126c9e2be55Smrg	TUSaveTocFile(toc);
1127c9e2be55Smrg    } else XtFree(ptr);
1128c9e2be55Smrg}
1129c9e2be55Smrg
1130c9e2be55Smrg
1131c9e2be55Smrg
1132c9e2be55SmrgMsg TocMsgFromId(Toc toc, int msgid)
1133c9e2be55Smrg{
1134c9e2be55Smrg    int h, l, m;
1135c9e2be55Smrg    l = 0;
1136c9e2be55Smrg    h = toc->nummsgs - 1;
1137c9e2be55Smrg    if (h < 0) {
1138c9e2be55Smrg	if (app_resources.debug) {
1139c9e2be55Smrg	    char str[100];
1140c9e2be55Smrg	    (void)sprintf(str, "Toc is empty! folder=%s\n", toc->foldername);
1141c9e2be55Smrg	    DEBUG( str )
1142c9e2be55Smrg	}
1143c9e2be55Smrg	return NULL;
1144c9e2be55Smrg    }
1145c9e2be55Smrg    while (l < h - 1) {
1146c9e2be55Smrg	m = (l + h) / 2;
1147c9e2be55Smrg	if (toc->msgs[m]->msgid > msgid)
1148c9e2be55Smrg	    h = m;
1149c9e2be55Smrg	else
1150c9e2be55Smrg	    l = m;
1151c9e2be55Smrg    }
1152c9e2be55Smrg    if (toc->msgs[l]->msgid == msgid) return toc->msgs[l];
1153c9e2be55Smrg    if (toc->msgs[h]->msgid == msgid) return toc->msgs[h];
1154c9e2be55Smrg    if (app_resources.debug) {
1155c9e2be55Smrg	char str[100];
1156c9e2be55Smrg	(void) sprintf(str,
1157c9e2be55Smrg		      "TocMsgFromId search failed! hi=%d, lo=%d, msgid=%d\n",
1158c9e2be55Smrg		      h, l, msgid);
1159c9e2be55Smrg	DEBUG( str )
1160c9e2be55Smrg    }
1161c9e2be55Smrg    return NULL;
1162c9e2be55Smrg}
1163c9e2be55Smrg
1164d859ff80Smrg/* Sequence names are put on a stack which is specific to the folder.
1165c9e2be55Smrg * Sequence names are very volatile, so we make our own copies of the strings.
1166c9e2be55Smrg */
1167c9e2be55Smrg
1168c9e2be55Smrg/*ARGSUSED*/
1169c9e2be55Smrgvoid XmhPushSequence(
1170c9e2be55Smrg    Widget	w,
1171c9e2be55Smrg    XEvent	*event,
1172c9e2be55Smrg    String	*params,
1173c9e2be55Smrg    Cardinal	*count)
1174c9e2be55Smrg{
1175c9e2be55Smrg    Scrn	scrn = ScrnFromWidget(w);
1176c9e2be55Smrg    Toc		toc;
1177c9e2be55Smrg    Cardinal	i;
1178c9e2be55Smrg
1179c9e2be55Smrg    if (! (toc = scrn->toc)) return;
1180d859ff80Smrg
1181c9e2be55Smrg    if (*count == 0) {
1182c9e2be55Smrg	if (toc->selectseq)
1183c9e2be55Smrg	    Push(&toc->sequence_stack, XtNewString(toc->selectseq->name));
1184c9e2be55Smrg    }
1185c9e2be55Smrg    else
1186d859ff80Smrg	for (i=0; i < *count; i++)
1187c9e2be55Smrg	    Push(&toc->sequence_stack, XtNewString(params[i]));
1188c9e2be55Smrg}
1189c9e2be55Smrg
1190c9e2be55Smrg
1191c9e2be55Smrg/*ARGSUSED*/
1192c9e2be55Smrgvoid XmhPopSequence(
1193c9e2be55Smrg    Widget	w,		/* any widget on the screen of interest */
1194c9e2be55Smrg    XEvent	*event,
1195c9e2be55Smrg    String	*params,
1196c9e2be55Smrg    Cardinal	*count)
1197c9e2be55Smrg{
1198c9e2be55Smrg    Scrn	scrn = ScrnFromWidget(w);
1199c9e2be55Smrg    char	*seqname;
1200c9e2be55Smrg    Widget	sequenceMenu, selected, original;
1201c9e2be55Smrg    Button	button;
1202c9e2be55Smrg    Sequence	sequence;
1203c9e2be55Smrg
1204c9e2be55Smrg    if ((seqname = Pop(&scrn->toc->sequence_stack)) != NULL) {
1205c9e2be55Smrg
1206c9e2be55Smrg	button = BBoxFindButtonNamed(scrn->mainbuttons,
1207c9e2be55Smrg				     MenuBoxButtons[XMH_SEQUENCE].button_name);
1208c9e2be55Smrg	sequenceMenu = BBoxMenuOfButton(button);
1209c9e2be55Smrg
1210c9e2be55Smrg	if ((selected = XawSimpleMenuGetActiveEntry(sequenceMenu)))
1211c9e2be55Smrg	    ToggleMenuItem(selected, False);
1212c9e2be55Smrg
1213c9e2be55Smrg	if ((original = XtNameToWidget(sequenceMenu, seqname))) {
1214c9e2be55Smrg	    ToggleMenuItem(original, True);
1215c9e2be55Smrg	    sequence = TocGetSeqNamed(scrn->toc, seqname);
1216c9e2be55Smrg	    TocSetSelectedSequence(scrn->toc, sequence);
1217c9e2be55Smrg	}
1218c9e2be55Smrg	XtFree(seqname);
1219c9e2be55Smrg    }
1220c9e2be55Smrg}
1221