|
|
1.1 root 1: #ifndef lint
2: static char rcs_id[] = "$Header: tocutil.c,v 1.14 87/09/11 08:19:27 toddb Exp $";
3: #endif lint
4: /*
5: * COPYRIGHT 1987
6: * DIGITAL EQUIPMENT CORPORATION
7: * MAYNARD, MASSACHUSETTS
8: * ALL RIGHTS RESERVED.
9: *
10: * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
11: * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
12: * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
13: * ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
14: *
15: * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS,
16: * APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT
17: * SET FORTH ABOVE.
18: *
19: *
20: * Permission to use, copy, modify, and distribute this software and its
21: * documentation for any purpose and without fee is hereby granted, provided
22: * that the above copyright notice appear in all copies and that both that
23: * copyright notice and this permission notice appear in supporting documentation,
24: * and that the name of Digital Equipment Corporation not be used in advertising
25: * or publicity pertaining to distribution of the software without specific,
26: * written prior permission.
27: */
28:
29: /* tocutil.c -- internal routines for toc stuff. */
30:
31: #include "xmh.h"
32: #include "toc.h"
33: #include "tocutil.h"
34: #include "tocintrnl.h"
35: #include <sys/file.h>
36:
37: Toc TUMalloc()
38: {
39: Toc toc;
40: toc = (Toc) XtMalloc(sizeof(TocRec));
41: bzero((char *)toc, (int) sizeof(TocRec));
42: toc->msgs = (Msg *) XtMalloc(1);
43: toc->seqlist = (Sequence *) XtMalloc(1);
44: toc->validity = unknown;
45: return toc;
46: }
47:
48:
49: /* Returns TRUE if the scan file for the given toc is out of date. */
50:
51: int TUScanFileOutOfDate(toc)
52: Toc toc;
53: {
54: return LastModifyDate(toc->path) > toc->lastreaddate;
55: }
56:
57:
58: /* Make sure the shown sequence buttons correspond exactly to the sequences
59: for this toc. If not, then rebuild the buttonbox. */
60:
61: static void CheckSeqButtons(toc)
62: Toc toc;
63: {
64: Scrn scrn = toc->scrn;
65: int i, numinbox;
66: int rebuild;
67: extern void PrepareDoubleClickSequence();
68: if (scrn == NULL) return;
69: rebuild = FALSE;
70: numinbox = BBoxNumButtons(scrn->seqbuttons);
71: if (numinbox != toc->numsequences)
72: rebuild = TRUE;
73: else {
74: for (i=0 ; i<toc->numsequences && !rebuild; i++)
75: rebuild =
76: strcmp(toc->seqlist[i]->name,
77: BBoxNameOfButton(BBoxButtonNumber(scrn->seqbuttons,
78: i)));
79: }
80: if (rebuild) {
81: BBoxStopUpdate(scrn->seqbuttons);
82: for (i = 1; i < numinbox ; i++)
83: BBoxDeleteButton(BBoxButtonNumber(scrn->seqbuttons, 1));
84: for (i = (numinbox ? 1 : 0); i < toc->numsequences; i++)
85: BBoxAddButton(scrn->seqbuttons, toc->seqlist[i]->name,
86: PrepareDoubleClickSequence, 999, TRUE);
87: BBoxStartUpdate(scrn->seqbuttons);
88: }
89: if (scrn->seqbuttons)
90: BBoxSetRadio(scrn->seqbuttons,
91: BBoxFindButtonNamed(scrn->seqbuttons,
92: toc->viewedseq->name));
93: }
94:
95:
96:
97: void TUScanFileForToc(toc)
98: Toc toc;
99: {
100: static Arg arglist[] = {
101: {XtNlabel, NULL},
102: {XtNx, (XtArgVal) 30},
103: {XtNy, (XtArgVal) 30}
104: };
105:
106: Window parent, label;
107: Scrn scrn;
108: char **argv, str[100], str2[10];
109: if (toc) {
110: TUGetFullFolderInfo(toc);
111: scrn = toc->scrn;
112: if (!scrn) scrn = scrnList[0];
113: parent = scrn->tocwindow;
114: if (!parent) parent = scrn->window;
115: (void) sprintf(str, "Rescanning %s", toc->foldername);
116: arglist[0].value = (XtArgVal) str;
117: label = XtLabelCreate(DISPLAY parent, arglist, XtNumber(arglist));
118: QXMapWindow(theDisplay, label);
119: (void) XtSendExpose(DISPLAY label);
120: QXFlush(theDisplay);
121:
122: argv = MakeArgv(4);
123: argv[0] = "scan";
124: (void) sprintf(str, "+%s", toc->foldername);
125: argv[1] = str;
126: argv[2] = "-width";
127: (void) sprintf(str2, "%d", defTocWidth);
128: argv[3] = str2;
129: DoCommand(argv, (char *) NULL, toc->scanfile);
130: XtFree((char *) argv);
131:
132: (void) XtSendDestroyNotify(DISPLAY label);
133: QXDestroyWindow(theDisplay, label);
134: toc->validity = valid;
135: toc->curmsg = NULL; /* Get cur msg somehow! %%% */
136: }
137: }
138:
139:
140:
141: int TUGetMsgPosition(toc, msg)
142: Toc toc;
143: Msg msg;
144: {
145: int msgid, h, l, m;
146: char str[100];
147: msgid = msg->msgid;
148: l = 0;
149: h = toc->nummsgs - 1;
150: while (l < h - 1) {
151: m = (l + h) / 2;
152: if (toc->msgs[m]->msgid > msgid)
153: h = m;
154: else
155: l = m;
156: }
157: if (toc->msgs[l] == msg) return l;
158: if (toc->msgs[h] == msg) return h;
159: (void) sprintf(str, "TUGetMsgPosition search failed! hi=%d, lo=%d, msgid=%d",
160: h, l, msgid);
161: Punt(str);
162: return 0; /* Keep lint happy. */
163: }
164:
165:
166: void TUResetTocLabel(scrn)
167: Scrn scrn;
168: {
169: char str[500];
170: Toc toc;
171: if (scrn) {
172: toc = scrn->toc;
173: if (toc == NULL)
174: (void) strcpy(str, " ");
175: else {
176: if (toc->stopupdate) {
177: toc->needslabelupdate = TRUE;
178: return;
179: }
180: (void) sprintf(str, "%s:%s", toc->foldername,
181: toc->viewedseq->name);
182: toc->needslabelupdate = FALSE;
183: }
184: ChangeLabel(scrn->toclabel, str);
185: }
186: }
187:
188:
189: /* A major toc change has occured; redisplay it. (This also should work even
190: if we now have a new source to display stuff from.) */
191:
192: void TURedisplayToc(scrn)
193: Scrn scrn;
194: {
195: Toc toc;
196: int lines, width, height;
197: XtTextPosition position;
198: if (scrn != NULL && scrn->tocwindow != NULL) {
199: toc = scrn->toc;
200: if (toc) {
201: if (toc->stopupdate) {
202: toc->needsrepaint = TRUE;
203: return;
204: }
205: GetWindowSize(scrn->tocwindow, &width, &height);
206: lines = scrn->tocsink->maxLines(scrn->tocsink, height);
207: position = toc->source->getLastPos(toc->source);
208: position = toc->source->scan(toc->source, position, XtstEOL,
209: XtsdLeft, lines, FALSE);
210: XtTextNewSource(DISPLAY scrn->tocwindow, toc->source, position);
211: TocSetCurMsg(toc, TocGetCurMsg(toc));
212: CheckSeqButtons(toc);
213: toc->needsrepaint = FALSE;
214: } else {
215: XtTextNewSource(DISPLAY scrn->tocwindow, NullSource, (XtTextPosition) 0);
216: }
217: }
218: }
219:
220:
221:
222: void TULoadSeqLists(toc)
223: Toc toc;
224: {
225: Sequence seq;
226: FILEPTR fid;
227: char str[500], *ptr, *ptr2, viewed[500];
228: int i;
229: if (toc->viewedseq) (void) strcpy(viewed, toc->viewedseq->name);
230: else *viewed = 0;
231: for (i = 0; i < toc->numsequences; i++) {
232: seq = toc->seqlist[i];
233: XtFree((char *) seq->name);
234: if (seq->mlist) FreeMsgList(seq->mlist);
235: XtFree((char *)seq);
236: }
237: toc->numsequences = 1;
238: toc->seqlist = (Sequence *) XtRealloc((char *) toc->seqlist,
239: sizeof(Sequence));
240: seq = toc->seqlist[0] = (Sequence) XtMalloc(sizeof(SequenceRec));
241: bzero((char *) seq, sizeof(SequenceRec));
242: seq->name = MallocACopy("all");
243: seq->mlist = NULL;
244: toc->viewedseq = seq;
245: (void) sprintf(str, "%s/.mh_sequences", toc->path);
246: fid = myfopen(str, "r");
247: if (fid) {
248: while (ptr = ReadLine(fid)) {
249: ptr2 = index(ptr, ':');
250: if (ptr2) {
251: *ptr2 = 0;
252: if (strcmp(ptr, "all") != 0 &&
253: strcmp(ptr, "cur") != 0 &&
254: strcmp(ptr, "unseen") != 0) {
255: toc->numsequences++;
256: toc->seqlist = (Sequence *)
257: XtRealloc((char *) toc->seqlist,
258: (unsigned) toc->numsequences * sizeof(Sequence));
259: seq = toc->seqlist[toc->numsequences - 1] =
260: (Sequence) XtMalloc(sizeof(SequenceRec));
261: bzero((char *) seq, sizeof(SequenceRec));
262: seq->name = MallocACopy(ptr);
263: seq->mlist = StringToMsgList(toc, ptr2 + 1);
264: if (strcmp(seq->name, viewed) == 0) {
265: toc->viewedseq = seq;
266: *viewed = 0;
267: }
268: }
269: }
270: }
271: (void) myfclose(fid);
272: }
273: }
274:
275:
276:
277: /* Refigure what messages are visible. Also makes sure we're displaying the
278: correct set of seq buttons. */
279:
280: void TURefigureWhatsVisible(toc)
281: Toc toc;
282: {
283: MsgList mlist;
284: Msg msg, oldcurmsg;
285: int i, w, changed, newval, msgid;
286: Sequence seq = toc->viewedseq;
287: mlist = seq->mlist;
288: oldcurmsg = toc->curmsg;
289: TocSetCurMsg(toc, (Msg)NULL);
290: w = 0;
291: changed = FALSE;
292: CheckSeqButtons(toc);
293: for (i = 0; i < toc->nummsgs; i++) {
294: msg = toc->msgs[i];
295: msgid = msg->msgid;
296: while (mlist && mlist->msglist[w] && mlist->msglist[w]->msgid < msgid)
297: w++;
298: newval = (!mlist || mlist->msglist[w]->msgid == msgid);
299: if (newval != msg->visible) {
300: changed = TRUE;
301: msg->visible = newval;
302: }
303: }
304: if (changed) {
305: TURefigureTocPositions(toc);
306: if (oldcurmsg) {
307: if (!oldcurmsg->visible) {
308: toc->curmsg = TocMsgAfter(toc, oldcurmsg);
309: if (toc->curmsg == NULL)
310: toc->curmsg = TocMsgBefore(toc, oldcurmsg);
311: } else toc->curmsg = oldcurmsg;
312: }
313: TURedisplayToc(toc->scrn);
314: } else TocSetCurMsg(toc, oldcurmsg);
315: TUResetTocLabel(toc->scrn);
316: }
317:
318:
319: /* (Re)load the toc from the scanfile. If reloading, this makes efforts to
320: keep the fates of msgs, and to keep msgs that are being edited. Note that
321: this routine must know of all places that msg ptrs are stored; it expects
322: them to be kept only in tocs, in scrns, and in msg sequences. */
323:
324: #define SeemsIdentical(msg1, msg2) ((msg1)->msgid == (msg2)->msgid && \
325: ((msg1)->temporary || (msg2)->temporary ||\
326: strcmp((msg1)->buf, (msg2)->buf) == 0))
327:
328: void TULoadTocFile(toc)
329: Toc toc;
330: {
331: int maxmsgs, l, orignummsgs, i, j, origcurmsgid;
332: FILEPTR fid;
333: XtTextPosition position;
334: char *ptr;
335: Msg msg, curmsg;
336: Msg *origmsgs;
337:
338: TocStopUpdate(toc);
339: toc->lastreaddate = CurrentDate();
340: if (toc->curmsg) {
341: origcurmsgid = toc->curmsg->msgid;
342: TocSetCurMsg(toc, (Msg)NULL);
343: } else origcurmsgid = 0;
344: fid = FOpenAndCheck(toc->scanfile, "r");
345: maxmsgs = 10;
346: orignummsgs = toc->nummsgs;
347: toc->nummsgs = 0;
348: origmsgs = toc->msgs;
349: toc->msgs = (Msg *) XtMalloc((unsigned) maxmsgs * sizeof(Msg));
350: position = 0;
351: i = 0;
352: curmsg = NULL;
353: while (ptr = ReadLineWithCR(fid)) {
354: toc->msgs[toc->nummsgs++] = msg = (Msg) XtMalloc(sizeof(MsgRec));
355: bzero((char *) msg, sizeof(MsgRec));
356: l = strlen(ptr);
357: msg->toc = toc;
358: msg->position = position;
359: msg->length = l;
360: msg->buf = MallocACopy(ptr);
361: msg->msgid = atoi(ptr);
362: if (msg->msgid == origcurmsgid)
363: curmsg = msg;
364: msg->buf[MARKPOS] = ' ';
365: position += l;
366: msg->changed = FALSE;
367: msg->fate = Fignore;
368: msg->desttoc = NULL;
369: msg->visible = TRUE;
370: if (toc->nummsgs >= maxmsgs) {
371: maxmsgs += 100;
372: toc->msgs = (Msg *) XtRealloc((char *) toc->msgs,
373: (unsigned) maxmsgs * sizeof(Msg));
374: }
375: while (i < orignummsgs && origmsgs[i]->msgid < msg->msgid) i++;
376: if (i < orignummsgs) {
377: origmsgs[i]->buf[MARKPOS] = ' ';
378: if (SeemsIdentical(origmsgs[i], msg))
379: MsgSetFate(msg, origmsgs[i]->fate, origmsgs[i]->desttoc);
380: }
381: }
382: toc->length = toc->origlength = toc->lastPos = position;
383: toc->msgs = (Msg *) XtRealloc((char *) toc->msgs,
384: (unsigned) toc->nummsgs * sizeof(Msg));
385: (void) myfclose(fid);
386: if (toc->source == NULL)
387: toc->source = TSourceCreate(toc);
388: for (i=0 ; i<numScrns ; i++) {
389: msg = scrnList[i]->msg;
390: if (msg && msg->toc == toc) {
391: for (j=0 ; j<toc->nummsgs ; j++) {
392: if (SeemsIdentical(toc->msgs[j], msg)) {
393: msg->position = toc->msgs[j]->position;
394: msg->visible = TRUE;
395: ptr = toc->msgs[j]->buf;
396: *(toc->msgs[j]) = *msg;
397: toc->msgs[j]->buf = ptr;
398: scrnList[i]->msg = toc->msgs[j];
399: break;
400: }
401: }
402: if (j >= toc->nummsgs) {
403: msg->temporary = FALSE; /* Don't try to auto-delete msg. */
404: MsgSetScrnForce(msg, (Scrn) NULL);
405: }
406: }
407: }
408: for (i=0 ; i<orignummsgs ; i++)
409: MsgFree(origmsgs[i]);
410: XtFree((char *)origmsgs);
411: TocSetCurMsg(toc, curmsg);
412: TULoadSeqLists(toc);
413: TocStartUpdate(toc);
414: }
415:
416:
417: void TUSaveTocFile(toc)
418: Toc toc;
419: {
420: extern long lseek();
421: Msg msg;
422: int fid;
423: int i;
424: XtTextPosition position;
425: char c;
426: if (toc->stopupdate) {
427: toc->needscachesave = TRUE;
428: return;
429: }
430: fid = -1;
431: position = 0;
432: for (i = 0; i < toc->nummsgs; i++) {
433: msg = toc->msgs[i];
434: if (fid < 0 && msg->changed) {
435: fid = myopen(toc->scanfile, O_RDWR, 0666);
436: (void) lseek(fid, (long)position, 0);
437: }
438: if (fid >= 0) {
439: c = msg->buf[MARKPOS];
440: msg->buf[MARKPOS] = ' ';
441: (void) write(fid, msg->buf, msg->length);
442: msg->buf[MARKPOS] = c;
443: }
444: position += msg->length;
445: }
446: if (fid < 0 && toc->length != toc->origlength)
447: fid = myopen(toc->scanfile, O_RDWR, 0666);
448: if (fid >= 0) {
449: (void) ftruncate(fid, toc->length);
450: toc->origlength = toc->length;
451: (void) myclose(fid);
452: } else
453: (void) utime(toc->scanfile, (time_t *)NULL);
454: toc->needscachesave = FALSE;
455: toc->lastreaddate = CurrentDate();
456: }
457:
458:
459: void TUEnsureScanIsValidAndOpen(toc)
460: Toc toc;
461: {
462: if (toc) {
463: TUGetFullFolderInfo(toc);
464: if (TUScanFileOutOfDate(toc)) {
465: if (toc->source) {
466: XtFree((char *) toc->source);
467: toc->source = NULL;
468: }
469: TUScanFileForToc(toc);
470: }
471: if (toc->source == NULL)
472: TULoadTocFile(toc);
473: toc->validity = valid;
474: }
475: }
476:
477:
478:
479: /* Refigure all the positions, based on which lines are visible. */
480:
481: void TURefigureTocPositions(toc)
482: Toc toc;
483: {
484: int i;
485: Msg msg;
486: XtTextPosition position, length;
487: position = length = 0;
488: for (i=0; i<toc->nummsgs ; i++) {
489: msg = toc->msgs[i];
490: msg->position = position;
491: if (msg->visible) position += msg->length;
492: length += msg->length;
493: }
494: toc->lastPos = position;
495: toc->length = length;
496: }
497:
498:
499:
500: /* Make sure we've loaded ALL the folder info for this toc, including its
501: path and sequence lists. */
502:
503: void TUGetFullFolderInfo(toc)
504: Toc toc;
505: {
506: char str[500];
507: if (toc->path == NULL) {
508: (void) sprintf(str, "%s/%s", mailDir, toc->foldername);
509: toc->path = MallocACopy(str);
510: (void) sprintf(str, "%s/.xmhcache", toc->path);
511: toc->scanfile = MallocACopy(str);
512: toc->lastreaddate = LastModifyDate(toc->scanfile);
513: if (TUScanFileOutOfDate(toc))
514: toc->validity = invalid;
515: else {
516: toc->validity = valid;
517: TULoadTocFile(toc);
518: }
519: }
520: }
521:
522: /* Append a message to the end of the toc. It has the given scan line. This
523: routine will figure out the message number, and change the scan line
524: accordingly. */
525:
526: Msg TUAppendToc(toc, ptr)
527: Toc toc;
528: char *ptr;
529: {
530: char str[10];
531: Msg msg;
532: int msgid, i;
533: TUGetFullFolderInfo(toc);
534: if (toc->validity != valid)
535: return NULL;
536:
537: if (toc->nummsgs > 0)
538: msgid = toc->msgs[toc->nummsgs - 1]->msgid + 1;
539: else
540: msgid = 1;
541: (toc->nummsgs)++;
542: toc->msgs = (Msg *) XtRealloc((char *) toc->msgs,
543: (unsigned) toc->nummsgs * sizeof(Msg));
544: toc->msgs[toc->nummsgs - 1] = msg = (Msg) XtMalloc(sizeof(MsgRec));
545: bzero((char *) msg, (int) sizeof(MsgRec));
546: msg->toc = toc;
547: msg->buf = MallocACopy(ptr);
548: (void)sprintf(str, "%4d", msgid);
549: for (i=0; i<4 ; i++) msg->buf[i] = str[i];
550: msg->buf[MARKPOS] = ' ';
551: msg->msgid = msgid;
552: msg->position = toc->lastPos;
553: msg->length = strlen(ptr);
554: msg->changed = TRUE;
555: msg->fate = Fignore;
556: msg->desttoc = NULL;
557: if (toc->viewedseq == toc->seqlist[0]) {
558: msg->visible = TRUE;
559: toc->lastPos += msg->length;
560: }
561: else
562: msg->visible = FALSE;
563: toc->length += msg->length;
564: TURedisplayToc(toc->scrn);
565: TUSaveTocFile(toc);
566: return msg;
567: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.