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

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