source: trunk/third/xmh/msg.c @ 9660

Revision 9660, 23.9 KB checked in by ghudson, 28 years ago (diff)
From the 8.0 release: When sending messages, don't use -push and don't dehighlight send button until message really sent.
Line 
1/*
2 * $XConsortium: msg.c,v 2.49 91/07/24 20:28:31 converse Exp $
3 *
4 *
5 *                     COPYRIGHT 1987, 1989
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
16 * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN
17 * ADDITION TO THAT SET FORTH ABOVE.
18 *
19 * Permission to use, copy, modify, and distribute this software and its
20 * documentation for any purpose and without fee is hereby granted, provided
21 * that the above copyright notice appear in all copies and that both that
22 * copyright notice and this permission notice appear in supporting
23 * documentation, and that the name of Digital Equipment Corporation not be
24 * used in advertising or publicity pertaining to distribution of the software
25 * without specific, written prior permission.
26 */
27
28/* msgs.c -- handle operations on messages. */
29
30#include <X11/Xaw/Cardinals.h>
31
32#include "xmh.h"
33#include "tocintrnl.h"
34
35static int SetScrn();
36
37/*      Function Name: SetEditable
38 *      Description: Sets the editable flag for this message.
39 *      Arguments: msg - the message.
40 *                 edit - set editable to this.
41 *      Returns: none
42 */
43
44static void
45SetEditable(msg, edit)
46Msg msg;
47Boolean edit;
48{
49  Arg args[1];
50
51  if (edit)
52    XtSetArg(args[0], XtNeditType, XawtextEdit);
53  else
54    XtSetArg(args[0], XtNeditType, XawtextRead);
55
56  XtSetValues(msg->source, args, ONE);
57}
58
59/*      Function Name: IsEditable
60 *      Description: Returns true if this is an editable message.
61 *      Arguments: msg - the message to edit.
62 *      Returns: TRUE if editable.
63 */
64
65static Boolean
66IsEditable(msg)
67Msg msg;
68{
69  Arg args[1];
70  XawTextEditType type;
71
72  XtSetArg(args[0], XtNeditType, &type);
73  XtGetValues(msg->source, args, ONE);
74
75  return(type == XawtextEdit);
76}
77
78/* Return the user-viewable name of the given message. */
79
80static char *NameOfMsg(msg)
81Msg msg;
82{
83    static char result[100];
84    (void) sprintf(result, "%s:%d", msg->toc->foldername, msg->msgid);
85    return result;
86}
87
88
89/* Update the message titlebar in the given scrn. */
90
91static void ResetMsgLabel(scrn)
92Scrn scrn;
93{
94    Msg msg;
95    char str[200];
96    if (scrn) {
97        msg = scrn->msg;
98        if (msg == NULL) (void) strcpy(str, app_resources.banner);
99        else {
100            (void) strcpy(str, NameOfMsg(msg));
101            switch (msg->fate) {
102              case Fdelete:
103                (void) strcat(str, " -> *Delete*");
104                break;
105              case Fcopy:
106              case Fmove:
107                (void) strcat(str, " -> ");
108                (void) strcat(str, msg->desttoc->foldername);
109                if (msg->fate == Fcopy)
110                    (void) strcat(str, " (Copy)");
111                break;
112            }
113            if (msg->temporary) (void)strcat(str, " [Temporary]");
114        }
115        ChangeLabel((Widget) scrn->viewlabel, str);
116    }
117}
118
119
120/* A major msg change has occured; redisplay it.  (This also should
121work even if we now have a new source to display stuff from.)  This
122routine arranges to hide boring headers, and also will set the text
123insertion point to the proper place if this is a composition and we're
124viewing it for the first time. */
125
126static void RedisplayMsg(scrn)
127Scrn scrn;
128{
129    Msg msg;
130    XawTextPosition startPos, lastPos, nextPos;
131    int length; char str[100];
132    XawTextBlock block;
133    if (scrn) {
134        msg = scrn->msg;
135        if (msg) {
136            startPos = 0;
137            if (app_resources.hide_boring_headers && scrn->kind != STcomp) {
138                lastPos = XawTextSourceScan(msg->source, (XawTextPosition) 0,
139                                            XawstAll, XawsdRight, 1, FALSE);
140                while (startPos < lastPos) {
141                    nextPos = startPos;
142                    length = 0;
143                    while (length < 8 && nextPos < lastPos) {
144                        nextPos = XawTextSourceRead(msg->source, nextPos,
145                                                    &block, 8 - length);
146                        (void) strncpy(str + length, block.ptr, block.length);
147                        length += block.length;
148                    }
149                    if (length == 8) {
150                        if (strncmp(str, "From:", 5) == 0 ||
151                            strncmp(str, "To:", 3) == 0 ||
152                            strncmp(str, "Date:", 5) == 0 ||
153                            strncmp(str, "Subject:", 8) == 0) break;
154                    }
155                    startPos = XawTextSourceScan(msg->source, startPos,
156                                                XawstEOL, XawsdRight, 1, TRUE);
157                }
158                if (startPos >= lastPos) startPos = 0;
159            }
160            XawTextSetSource(scrn->viewwidget, msg->source, startPos);
161            if (msg->startPos > 0) {
162                XawTextSetInsertionPoint(scrn->viewwidget, msg->startPos);
163                msg->startPos = 0; /* Start in magic place only once. */
164            }
165        } else {
166            XawTextSetSource(scrn->viewwidget, PNullSource,
167                             (XawTextPosition)0);
168        }
169    }
170}
171
172
173
174static char tempDraftFile[100] = "";
175
176/* Temporarily move the draftfile somewhere else, so we can exec an mh
177   command that affects it. */
178
179static void TempMoveDraft()
180{
181    char *ptr;
182    if (FileExists(draftFile)) {
183        do {
184            ptr = MakeNewTempFileName();
185            (void) strcpy(tempDraftFile, draftFile);
186            (void) strcpy(rindex(tempDraftFile, '/'), rindex(ptr, '/'));
187        } while (FileExists(tempDraftFile));
188        RenameAndCheck(draftFile, tempDraftFile);
189    }
190}
191
192
193
194/* Restore the draftfile from its temporary hiding place. */
195
196static void RestoreDraft()
197{
198    if (*tempDraftFile) {
199        RenameAndCheck(tempDraftFile, draftFile);
200        *tempDraftFile = 0;
201    }
202}
203
204
205
206/* Public routines */
207
208
209/* Given a message, return the corresponding filename. */
210
211char *MsgFileName(msg)
212Msg msg;
213{
214    static char result[500];
215    (void) sprintf(result, "%s/%d", msg->toc->path, msg->msgid);
216    return result;
217}
218
219
220
221/* Save any changes to a message.  Also calls the toc routine to update the
222   scanline for this msg.  Returns True if saved, false otherwise. */
223
224MsgSaveChanges(msg, dobuttons)
225Msg msg;
226int dobuttons;
227{
228    int i;
229    if (msg->source) {
230        if (XawAsciiSave(msg->source)) {
231            for (i=0; i < (int) msg->num_scrns; i++) {
232                if (dobuttons)
233                    EnableProperButtons(msg->scrn[i]);
234            }
235            if (!msg->temporary)
236                TocMsgChanged(msg->toc, msg);
237            return True;
238        }
239        else {
240            char str[256];
241            (void) sprintf(str, "Cannot save changes to \"%s/%d\"!",
242                           msg->toc->foldername, msg->msgid);
243            PopupError((Widget)NULL, str);
244            return False;
245        }
246    }
247    Feep();
248    return False;
249}
250
251
252/*
253 * Show the given message in the given scrn.  If a message is changed, and we
254 * are removing it from any scrn, then ask for confirmation first.  If the
255 * scrn was showing a temporary msg that is not being shown in any other scrn,
256 * it is deleted.  If scrn is NULL, then remove the message from every scrn
257 * that's showing it.
258 */
259
260
261/*ARGSUSED*/
262static void ConfirmedNoScrn(widget, client_data, call_data)
263    Widget      widget;         /* unused */
264    XtPointer   client_data;
265    XtPointer   call_data;      /* unused */
266{
267    Msg         msg = (Msg) client_data;
268    register int i;
269
270    for (i=msg->num_scrns - 1 ; i >= 0 ; i--)
271        SetScrn((Msg)NULL, msg->scrn[i], TRUE, (XtCallbackList) NULL,
272                (XtCallbackList) NULL);
273}
274
275
276static void RemoveMsgConfirmed(scrn)
277    Scrn        scrn;
278{
279    if (scrn->kind == STtocAndView && MsgChanged(scrn->msg)) {
280        Arg     args[1];
281        XtSetArg(args[0], XtNtranslations, scrn->read_translations);
282        XtSetValues(scrn->viewwidget, args, (Cardinal) 1);
283    }
284    scrn->msg->scrn[0] = NULL;
285    scrn->msg->num_scrns = 0;
286    XawTextSetSource(scrn->viewwidget, PNullSource, (XawTextPosition) 0);
287    XtDestroyWidget(scrn->msg->source);
288    scrn->msg->source = NULL;
289    if (scrn->msg->temporary) {
290        (void) unlink(MsgFileName(scrn->msg));
291        TocRemoveMsg(scrn->msg->toc, scrn->msg);
292        MsgFree(scrn->msg);
293    }           
294}
295
296
297static void SetScrnNewMsg(msg, scrn)
298    Msg         msg;
299    Scrn        scrn;
300{
301   scrn->msg = msg;
302   if (msg == NULL) {
303        XawTextSetSource(scrn->viewwidget, PNullSource, (XawTextPosition) 0);
304        ResetMsgLabel(scrn);
305        EnableProperButtons(scrn);
306        if (scrn->kind != STtocAndView)
307            StoreWindowName(scrn, progName);
308    } else {
309        msg->num_scrns++;
310        msg->scrn = (Scrn *) XtRealloc((char *)msg->scrn,
311                                       (unsigned) sizeof(Scrn)*msg->num_scrns);
312        msg->scrn[msg->num_scrns - 1] = scrn;
313        if (msg->source == NULL)
314            msg->source = CreateFileSource(scrn->viewwidget, MsgFileName(msg),
315                                           scrn->kind == STcomp);
316        ResetMsgLabel(scrn);
317        RedisplayMsg(scrn);
318        EnableProperButtons(scrn);
319        if (scrn->kind != STtocAndView)
320            StoreWindowName(scrn, NameOfMsg(msg));
321    }
322}
323
324typedef struct _MsgAndScrn {
325    Msg         msg;
326    Scrn        scrn;
327} MsgAndScrnRec, *MsgAndScrn;
328
329/*ARGSUSED*/
330static void ConfirmedWithScrn(widget, client_data, call_data)
331    Widget      widget;         /* unused */
332    XtPointer   client_data;
333    XtPointer   call_data;      /* unused */
334{
335    MsgAndScrn  mas = (MsgAndScrn) client_data;
336    RemoveMsgConfirmed(mas->scrn);
337    SetScrnNewMsg(mas->msg, mas->scrn);
338    XtFree((char *) mas);
339}
340   
341   
342static int SetScrn(msg, scrn, force, confirms, cancels)
343    Msg         msg;
344    Scrn        scrn;
345    Boolean     force;                  /* if true, force msg set scrn */
346    XtCallbackList      confirms;       /* callbacks upon confirmation */
347    XtCallbackList      cancels;        /* callbacks upon cancellation */
348{
349    register int i, num_scrns;
350    static XtCallbackRec yes_callbacks[] = {
351        {(XtCallbackProc) NULL, (XtPointer) NULL},
352        {(XtCallbackProc) NULL, (XtPointer) NULL},
353        {(XtCallbackProc) NULL, (XtPointer) NULL}
354    };
355
356    if (scrn == NULL) {
357        if (msg == NULL || msg->num_scrns == 0) return 0;
358        if (!force && XawAsciiSourceChanged(msg->source)) {
359            char str[100];
360            (void) sprintf(str,
361                           "Are you sure you want to remove changes to %s?",
362                           NameOfMsg(msg));
363
364            yes_callbacks[0].callback = ConfirmedNoScrn;
365            yes_callbacks[0].closure = (XtPointer) msg;
366            yes_callbacks[1].callback = confirms[0].callback;
367            yes_callbacks[1].closure = confirms[0].closure;
368
369            PopupConfirm((Widget) NULL, str, yes_callbacks, cancels);
370            return NEEDS_CONFIRMATION;
371        }
372        ConfirmedNoScrn((Widget)NULL, (XtPointer) msg, (XtPointer) NULL);
373        return 0;
374    }
375
376    if (scrn->msg == msg) return 0;
377
378    if (scrn->msg) {
379        num_scrns = scrn->msg->num_scrns;
380        for (i=0 ; i<num_scrns ; i++)
381            if (scrn->msg->scrn[i] == scrn) break;
382        if (i >= num_scrns) Punt("Couldn't find scrn in SetScrn!");
383        if (num_scrns > 1)
384            scrn->msg->scrn[i] = scrn->msg->scrn[--(scrn->msg->num_scrns)];
385        else {
386            if (!force && XawAsciiSourceChanged(scrn->msg->source)) {
387                char            str[100];
388                MsgAndScrn      cb_data;
389
390                cb_data = XtNew(MsgAndScrnRec);
391                cb_data->msg = msg;
392                cb_data->scrn = scrn;
393                (void)sprintf(str,
394                              "Are you sure you want to remove changes to %s?",
395                              NameOfMsg(scrn->msg));
396                yes_callbacks[0].callback = ConfirmedWithScrn;
397                yes_callbacks[0].closure = (XtPointer) cb_data;
398                yes_callbacks[1].callback = confirms[0].callback;
399                yes_callbacks[1].closure = confirms[0].closure;
400                PopupConfirm(scrn->viewwidget, str, yes_callbacks, cancels);
401                return NEEDS_CONFIRMATION;
402            }
403            RemoveMsgConfirmed(scrn);
404        }
405    }
406    SetScrnNewMsg(msg, scrn);
407    return 0;
408}
409
410
411
412/* Associate the given msg and scrn, asking for confirmation if necessary. */
413
414int MsgSetScrn(msg, scrn, confirms, cancels)
415Msg msg;
416Scrn scrn;
417XtCallbackList  confirms;
418XtCallbackList  cancels;
419{
420    return SetScrn(msg, scrn, FALSE, confirms, cancels);
421}
422
423
424/* Same as above, but with the extra information that the message is actually
425   a composition.  (Nothing currently takes advantage of that extra fact.) */
426
427void MsgSetScrnForComp(msg, scrn)
428Msg msg;
429Scrn scrn;
430{
431    (void) SetScrn(msg, scrn, FALSE, (XtCallbackList) NULL,
432                   (XtCallbackList) NULL);
433}
434
435
436/* Associate the given msg and scrn, even if it means losing some unsaved
437   changes. */
438
439void MsgSetScrnForce(msg, scrn)
440Msg msg;
441Scrn scrn;
442{
443    (void) SetScrn(msg, scrn, TRUE, (XtCallbackList) NULL,
444                   (XtCallbackList) NULL);
445}
446
447
448
449/* Set the fate of the given message. */
450
451void MsgSetFate(msg, fate, desttoc)
452  Msg msg;
453  FateType fate;
454  Toc desttoc;
455{
456    Toc toc = msg->toc;
457    XawTextBlock block;
458    int i;
459    msg->fate = fate;
460    msg->desttoc = desttoc;
461    if (fate == Fignore && msg == msg->toc->curmsg)
462        block.ptr = "+";
463    else {
464        switch (fate) {
465            case Fignore:       block.ptr = " "; break;
466            case Fcopy:         block.ptr = "C"; break;
467            case Fmove:         block.ptr = "^"; break;
468            case Fdelete:       block.ptr = "D"; break;
469        }
470    }
471    block.firstPos = 0;
472    block.format = FMT8BIT;
473    block.length = 1;
474    if (toc->stopupdate)
475        toc->needsrepaint = TRUE;
476    if (toc->num_scrns && msg->visible && !toc->needsrepaint &&
477            *block.ptr != msg->buf[MARKPOS])
478        (void)XawTextReplace(msg->toc->scrn[0]->tocwidget, /*%%%SourceReplace*/
479                            msg->position + MARKPOS,
480                            msg->position + MARKPOS + 1, &block);
481    else
482        msg->buf[MARKPOS] = *block.ptr;
483    for (i=0; i < (int) msg->num_scrns; i++)
484        ResetMsgLabel(msg->scrn[i]);
485}
486
487
488
489/* Get the fate of this message. */
490
491FateType MsgGetFate(msg, toc)
492Msg msg;
493Toc *toc;                       /* RETURN */
494{
495    if (toc) *toc = msg->desttoc;
496    return msg->fate;
497}
498
499
500/* Make this a temporary message. */
501
502void MsgSetTemporary(msg)
503Msg msg;
504{
505    int i;
506    msg->temporary = TRUE;
507    for (i=0; i < (int) msg->num_scrns; i++)
508        ResetMsgLabel(msg->scrn[i]);
509}
510
511
512/* Make this a permanent message. */
513
514void MsgSetPermanent(msg)
515Msg msg;
516{
517    int i;
518    msg->temporary = FALSE;
519    for (i=0; i < (int) msg->num_scrns; i++)
520        ResetMsgLabel(msg->scrn[i]);
521}
522
523
524
525/* Return the id# of this message. */
526
527int MsgGetId(msg)
528Msg msg;
529{
530    return msg->msgid;
531}
532
533
534/* Return the scanline for this message. */
535
536char *MsgGetScanLine(msg)
537Msg msg;
538{
539    return msg->buf;
540}
541
542
543
544/* Return the toc this message is in. */
545
546Toc MsgGetToc(msg)
547Msg msg;
548{
549    return msg->toc;
550}
551
552
553/* Set the reapable flag for this msg. */
554
555void MsgSetReapable(msg)
556Msg msg;
557{
558    int i;
559    msg->reapable = TRUE;
560    for (i=0; i < (int) msg->num_scrns; i++)
561        EnableProperButtons(msg->scrn[i]);
562}
563
564
565
566/* Clear the reapable flag for this msg. */
567
568void MsgClearReapable(msg)
569Msg msg;
570{
571    int i;
572    msg->reapable = FALSE;
573    for (i=0; i < (int) msg->num_scrns; i++)
574        EnableProperButtons(msg->scrn[i]);
575}
576
577
578/* Get the reapable value for this msg.  Returns TRUE iff the reapable flag
579   is set AND no changes have been made. */
580
581int MsgGetReapable(msg)
582Msg msg;
583{
584    return msg == NULL || (msg->reapable &&
585                           (msg->source == NULL ||
586                            !XawAsciiSourceChanged(msg->source)));
587}
588
589
590/* Make it possible to edit the given msg. */
591void MsgSetEditable(msg)
592Msg msg;
593{
594    int i;
595    if (msg && msg->source) {
596        SetEditable(msg, TRUE);
597        for (i=0; i < (int) msg->num_scrns; i++)
598            EnableProperButtons(msg->scrn[i]);
599    }
600}
601
602
603
604/* Turn off editing for the given msg. */
605
606void MsgClearEditable(msg)
607Msg msg;
608{
609    int i;
610    if (msg && msg->source) {
611        SetEditable(msg, FALSE);
612        for (i=0; i < (int) msg->num_scrns; i++)
613            EnableProperButtons(msg->scrn[i]);
614    }
615}
616
617
618
619/* Get whether the msg is editable. */
620
621int MsgGetEditable(msg)
622Msg msg;
623{
624    return msg && msg->source && IsEditable(msg);
625}
626
627
628/* Get whether the msg has changed since last saved. */
629
630int MsgChanged(msg)
631Msg msg;
632{
633    return msg && msg->source && XawAsciiSourceChanged(msg->source);
634}
635
636/* Call the given function when the msg changes. */
637
638void
639MsgSetCallOnChange(msg, func, param)
640Msg msg;
641void (*func)();
642XtPointer param;
643{
644  Arg args[1];
645  static XtCallbackRec cb[] = { {NULL, NULL}, {NULL, NULL} };
646
647  if (func != NULL) {
648    cb[0].callback = func;
649    cb[0].closure = param;
650    XtSetArg(args[0], XtNcallback, cb);
651  }
652  else
653    XtSetArg(args[0], XtNcallback, NULL);
654
655  XtSetValues(msg->source, args, (Cardinal) 1);
656
657}
658
659/* Send (i.e., mail) the given message as is.  First break it up into lines,
660   and copy it to a new file in the process.  The new file is one of 10
661   possible draft files; we rotate amoung the 10 so that the user can have up
662   to 10 messages being sent at once.  (Using a file in /tmp is a bad idea
663   because these files never actually get deleted, but renamed with some
664   prefix.  Also, these should stay in an area private to the user for
665   security.) */
666
667void MsgSend(msg)
668Msg msg;
669{
670    FILEPTR from;
671    FILEPTR to;
672    int     p, c, l, inheader, sendwidth, sendbreakwidth;
673    char   *ptr, *ptr2, **argv, str[100];
674    static sendcount = -1;
675    (void) MsgSaveChanges(msg, 0);
676    from = FOpenAndCheck(MsgFileName(msg), "r");
677    sendcount = (sendcount + 1) % 10;
678    (void) sprintf(str, "%s%d", xmhDraftFile, sendcount);
679    to = FOpenAndCheck(str, "w");
680    sendwidth = app_resources.send_line_width;
681    sendbreakwidth = app_resources.break_send_line_width;
682    inheader = TRUE;
683    while (ptr = ReadLine(from)) {
684        if (inheader) {
685            if (strncmpIgnoringCase(ptr, "sendwidth:", 10) == 0) {
686                if (atoi(ptr+10) > 0) sendwidth = atoi(ptr+10);
687                continue;
688            }
689            if (strncmpIgnoringCase(ptr, "sendbreakwidth:", 15) == 0) {
690                if (atoi(ptr+15) > 0) sendbreakwidth = atoi(ptr+15);
691                continue;
692            }
693            for (l = 0, ptr2 = ptr ; *ptr2 && !l ; ptr2++)
694                l = (*ptr2 != ' ' && *ptr2 != '\t' && *ptr != '-');
695            if (l) {
696                (void) fprintf(to, "%s\n", ptr);
697                continue;
698            }
699            inheader = FALSE;
700            if (sendbreakwidth < sendwidth) sendbreakwidth = sendwidth;
701        }
702        do {
703            for (p = c = l = 0, ptr2 = ptr;
704                 *ptr2 && c < sendbreakwidth;
705                 p++, ptr2++) {
706                 if (*ptr2 == ' ' && c < sendwidth)
707                     l = p;
708                 if (*ptr2 == '\t') {
709                     if (c < sendwidth) l = p;
710                     c += 8 - (c % 8);
711                 }
712                 else
713                 c++;
714             }
715            if (c < sendbreakwidth) {
716                (void) fprintf(to, "%s\n", ptr);
717                *ptr = 0;
718            }
719            else
720                if (l) {
721                    ptr[l] = 0;
722                    (void) fprintf(to, "%s\n", ptr);
723                    ptr += l + 1;
724                }
725                else {
726                    for (c = 0; c < sendwidth; ) {
727                        if (*ptr == '\t') c += 8 - (c % 8);
728                        else c++;
729                        (void) fputc(*ptr++, to);
730                    }
731                    (void) fputc('\n', to);
732                }
733        } while (*ptr);
734    }
735    (void) myfclose(from);
736    (void) myfclose(to);
737    argv = MakeArgv(2);
738    argv[0] = "send";
739    argv[1] = str;
740    DoCommand(argv, (char *) NULL, (char *) NULL);
741    XtFree((char *) argv);
742}
743
744
745/* Make the msg into the form for a generic composition.  Set msg->startPos
746   so that the text insertion point will be placed at the end of the first
747   line (which is usually the "To:" field). */
748
749void MsgLoadComposition(msg)
750Msg msg;
751{
752    static char *blankcomp = NULL; /* Array containing comp template */
753    static int compsize = 0;
754    static XawTextPosition startPos;
755    char *file, **argv;
756    int fid;
757    if (blankcomp == NULL) {
758        file = MakeNewTempFileName();
759        argv = MakeArgv(5);
760        argv[0] = "comp";
761        argv[1] = "-file";
762        argv[2] = file;
763        argv[3] = "-nowhatnowproc";
764        argv[4] = "-nodraftfolder";
765        DoCommand(argv, (char *) NULL, (char *) NULL);
766        XtFree((char *) argv);
767        compsize = GetFileLength(file);
768        if (compsize > 0) {
769            blankcomp = XtMalloc((Cardinal) compsize);
770            fid = myopen(file, O_RDONLY, 0666);
771            if (compsize != read(fid, blankcomp, compsize))
772                Punt("Error reading in MsgLoadComposition!");
773            (void) myclose(fid);
774            DeleteFileAndCheck(file);
775        } else {
776            blankcomp = "To: \n--------\n";
777            compsize = strlen(blankcomp);
778        }
779        startPos = index(blankcomp, '\n') - blankcomp;
780    }
781    fid = myopen(MsgFileName(msg), O_WRONLY | O_TRUNC | O_CREAT, 0666);
782    if (compsize != write(fid, blankcomp, compsize))
783        Punt("Error writing in MsgLoadComposition!");
784    (void) myclose(fid);
785    TocSetCacheValid(msg->toc);
786    msg->startPos = startPos;
787}
788
789
790
791/* Load a msg with a template of a reply to frommsg.  Set msg->startPos so
792   that the text insertion point will be placed at the beginning of the
793   message body. */
794
795void MsgLoadReply(msg, frommsg)
796Msg msg, frommsg;
797{
798    char **argv;
799    char str[100];
800    int status;
801
802    TempMoveDraft();
803    argv = MakeArgv(5);
804    argv[0] = "repl";
805    argv[1] = TocMakeFolderName(frommsg->toc);
806    (void) sprintf(str, "%d", frommsg->msgid);
807    argv[2] = str;
808    argv[3] = "-nowhatnowproc";
809    argv[4] = "-nodraftfolder";
810    status = DoCommand(argv, (char *) NULL, (char *) NULL);
811    XtFree(argv[1]);
812    XtFree((char*)argv);
813    if (!status) {
814        RenameAndCheck(draftFile, MsgFileName(msg));
815        RestoreDraft();
816        TocSetCacheValid(frommsg->toc); /* If -anno is set, this keeps us from
817                                           rescanning folder. */
818        TocSetCacheValid(msg->toc);
819        msg->startPos = GetFileLength(MsgFileName(msg));
820    }
821}
822
823
824
825/* Load a msg with a template of forwarding a list of messages.  Set
826   msg->startPos so that the text insertion point will be placed at the end
827   of the first line (which is usually a "To:" field). */
828
829void MsgLoadForward(scrn, msg, mlist)
830  Scrn scrn;
831  Msg msg;
832  MsgList mlist;
833{
834    char  **argv, str[100];
835    int     i;
836    TempMoveDraft();
837    argv = MakeArgv(4 + mlist->nummsgs);
838    argv[0] = "forw";
839    argv[1] = TocMakeFolderName(mlist->msglist[0]->toc);
840    for (i = 0; i < mlist->nummsgs; i++) {
841        (void) sprintf(str, "%d", mlist->msglist[i]->msgid);
842        argv[2 + i] = XtNewString(str);
843    }
844    argv[2 + i] = "-nowhatnowproc";
845    argv[3 + i] = "-nodraftfolder";
846    DoCommand(argv, (char *) NULL, (char *) NULL);
847    for (i = 1; i < 2 + mlist->nummsgs; i++)
848        XtFree((char *) argv[i]);
849    XtFree((char *) argv);
850    RenameAndCheck(draftFile, MsgFileName(msg));
851    RestoreDraft();
852    TocSetCacheValid(msg->toc);
853    msg->source = CreateFileSource(scrn->viewlabel, MsgFileName(msg), True);
854    msg->startPos = XawTextSourceScan(msg->source, (XawTextPosition) 0,
855                                      XawstEOL, XawsdRight, 1, False);
856}
857
858
859/* Load msg with a copy of frommsg. */
860
861void MsgLoadCopy(msg, frommsg)
862Msg msg, frommsg;
863{
864    char str[500];
865    (void)strcpy(str, MsgFileName(msg));
866    CopyFileAndCheck(MsgFileName(frommsg), str);
867    TocSetCacheValid(msg->toc);
868}
869
870/* Checkpoint the given message if it contains unsaved edits. */
871
872void MsgCheckPoint(msg)
873Msg msg;
874{
875    int len;
876    char file[500];
877
878    if (!msg || !msg->source || !IsEditable(msg) ||
879        !XawAsciiSourceChanged(msg->source))
880        return;
881
882    if (*app_resources.checkpoint_name_format == '/') {
883        (void) sprintf(file, app_resources.checkpoint_name_format, msg->msgid);
884    } else {
885        (void) sprintf(file, "%s/", msg->toc->path);
886        len = strlen(file);
887        (void) sprintf(file + len, app_resources.checkpoint_name_format,
888                       msg->msgid);
889    }
890    if (!XawAsciiSaveAsFile(msg->source, file)) {
891        char str[256];
892        (void) sprintf(str, "Unsaved edits cannot be checkpointed to %s.",
893                       file);
894        PopupError((Widget)NULL, str);
895    }
896    TocSetCacheValid(msg->toc);
897}
898
899/* Free the storage being used by the given msg. */
900
901void MsgFree(msg)
902Msg msg;
903{
904    XtFree(msg->buf);
905    XtFree((char *)msg);
906}
907
908/* Insert the associated message, if any, filtering it first */
909
910/*ARGSUSED*/
911void XmhInsert(w, event, params, num_params)
912    Widget      w;
913    XEvent      *event;
914    String      *params;
915    Cardinal    *num_params;
916{
917    Scrn scrn = ScrnFromWidget(w);
918    Msg msg = scrn->msg;
919    XawTextPosition pos;
920    XawTextBlock block;
921
922    if (msg == NULL || scrn->assocmsg == NULL) return;
923
924    if (app_resources.insert_filter && *app_resources.insert_filter) {
925        char command[1024];
926        char *argv[4];
927        argv[0] = "/bin/sh";
928        argv[1] = "-c";
929        sprintf(command, "%s %s", app_resources.insert_filter,
930                MsgFileName(scrn->assocmsg));
931        argv[2] = command;
932        argv[3] = 0;
933        block.ptr = DoCommandToString(argv);
934        block.length = strlen(block.ptr);
935    }
936    else {
937        /* default filter is equivalent to 'echo "<filename>"' */
938        block.ptr = XtNewString(MsgFileName(scrn->assocmsg));
939        block.length = strlen(block.ptr);
940    }
941    block.firstPos = 0;
942    block.format = FMT8BIT;
943    pos = XawTextGetInsertionPoint(scrn->viewwidget);
944    if (XawTextReplace(scrn->viewwidget, pos, pos, &block) != XawEditDone)
945        PopupError(scrn->parent, "Insertion failed!");
946    XtFree(block.ptr);
947}
948
949/*      Function Name: CreateFileSource
950 *      Description: Creates an AsciiSource for a file.
951 *      Arguments: w - the widget to create the source for.
952 *                 filename - the file to assign to this source.
953 *                 edit - if TRUE then this disk source is editable.
954 *      Returns: the source.
955 */
956
957Widget
958CreateFileSource(w, filename, edit)
959Widget w;
960String filename;
961Boolean edit;
962{
963  Arg arglist[10];
964  Cardinal num_args = 0;
965
966  XtSetArg(arglist[num_args], XtNtype, XawAsciiFile);  num_args++;
967  XtSetArg(arglist[num_args], XtNstring, filename);    num_args++;
968  if (edit)
969      XtSetArg(arglist[num_args], XtNeditType, XawtextEdit);
970  else
971      XtSetArg(arglist[num_args], XtNeditType, XawtextRead);
972  num_args++;
973
974  return(XtCreateWidget("textSource", asciiSrcObjectClass, w,
975                        arglist, num_args));
976}
977
Note: See TracBrowser for help on using the repository browser.