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