Annotation of researchv9/X11/src/X.V11R1/clients/xmh/msg.c, revision 1.1.1.1

1.1       root        1: #ifndef lint
                      2: static char rcs_id[] = "$Header: msg.c,v 1.18 87/08/20 11:14:28 swick 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: /* msgs.c -- handle operations on messages. */
                     30: 
                     31: #include "xmh.h"
                     32: #include "tocintrnl.h"
                     33: #include <sys/file.h>
                     34: 
                     35: #ifdef NOGRABFOCUS
                     36: /* Overload this Xlib routine, as the toolkit widgets use it directly. */
                     37: 
                     38: XSetInputFocus(d, w, r, t)
                     39:      Display d;
                     40:      Window w;
                     41:      int r;
                     42:      Time t;
                     43: {
                     44: }
                     45: #endif
                     46: 
                     47: 
                     48: /* Return the user-viewable name of the given message. */
                     49: 
                     50: static char *NameOfMsg(msg)
                     51: Msg msg;
                     52: {
                     53:     static char result[100];
                     54:     (void) sprintf(result, "%s:%d", msg->toc->foldername, msg->msgid);
                     55:     return result;
                     56: }
                     57: 
                     58: 
                     59: /* Update the message titlebar in the given scrn. */
                     60: 
                     61: static void ResetMsgLabel(scrn)
                     62: Scrn scrn;
                     63: {
                     64:     Msg msg;
                     65:     char str[200];
                     66:     if (scrn) {
                     67:        msg = scrn->msg;
                     68:        if (msg == NULL) (void) strcpy(str, Version());
                     69:        else {
                     70:            (void) strcpy(str, NameOfMsg(msg));
                     71:            switch (msg->fate) {
                     72:              case Fdelete:
                     73:                (void) strcat(str, " -> *Delete*");
                     74:                break;
                     75:              case Fcopy:
                     76:              case Fmove:
                     77:                (void) strcat(str, " -> ");
                     78:                (void) strcat(str, msg->desttoc->foldername);
                     79:                if (msg->fate == Fcopy)
                     80:                    (void) strcat(str, " (Copy)");
                     81:                break;
                     82:            }
                     83:            if (msg->temporary) (void)strcat(str, " [Temporary]");
                     84:        }
                     85:        ChangeLabel(scrn->viewlabel, str);
                     86:     }
                     87: }
                     88: 
                     89: 
                     90: /* A major msg change has occured; redisplay it.  (This also should
                     91: work even if we now have a new source to display stuff from.)  This
                     92: routine arranges to hide boring headers, and also will set the text
                     93: insertion point to the proper place if this is a composition and we're
                     94: viewing it for the first time. */
                     95: 
                     96: static void RedisplayMsg(scrn)
                     97: Scrn scrn;
                     98: {
                     99:     Msg msg;
                    100:     XtTextPosition startPos, lastPos, nextPos;
                    101:     int length; char str[100];
                    102:     XtTextBlock text;
                    103:     if (scrn) {
                    104:        msg = scrn->msg;
                    105:        if (msg) {
                    106:            startPos = 0;
                    107:            if (defHideBoringHeaders && scrn->kind != STcomp) {
                    108:                lastPos = msg->source->getLastPos(msg->source);
                    109:                while (startPos < lastPos) {
                    110:                    nextPos = startPos;
                    111:                    length = 0;
                    112:                    while (length < 8 && nextPos < lastPos) {
                    113:                        nextPos = (*msg->source->read)(msg->source, nextPos,
                    114:                                                       &text, 8 - length);
                    115:                        (void) strncpy(str + length, text.ptr, text.length);
                    116:                        length += text.length;
                    117:                    }
                    118:                    if (length == 8) {
                    119:                        if (strncmp(str, "From:", 5) == 0 ||
                    120:                            strncmp(str, "To:", 3) == 0 ||
                    121:                            strncmp(str, "Date:", 5) == 0 ||
                    122:                            strncmp(str, "Subject:", 8) == 0) break;
                    123:                    }
                    124:                    startPos = (*msg->source->scan)
                    125:                        (msg->source, startPos, XtstEOL, XtsdRight, 1,TRUE);
                    126:                }
                    127:            }
                    128:            if (startPos >= lastPos) startPos = 0;
                    129:            XtTextNewSource(DISPLAY scrn->viewwindow, msg->source, startPos);
                    130:            if (msg->startPos > 0) {
                    131: #ifdef X10
                    132:            /* Do an incredibly disgusting hack to make things display right.
                    133:               The X10 toolkit stinks. */
                    134:                MapScrn(scrn);
                    135:                EmptyEventQueue();
                    136: #endif X10
                    137:                XtTextSetInsertionPoint(DISPLAY scrn->viewwindow,
                    138:                                        msg->startPos);
                    139:                msg->startPos = 0; /* Start in magic place only once. */
                    140:            }
                    141:        } else {
                    142:            XtTextNewSource(DISPLAY scrn->viewwindow,
                    143:                            NullSource, (XtTextPosition) 0);
                    144:        }
                    145:     }
                    146: }
                    147: 
                    148: 
                    149: 
                    150: static char tempDraftFile[100] = "";
                    151: 
                    152: /* Temporarily move the draftfile somewhere else, so we can exec an mh
                    153:    command that affects it. */
                    154: 
                    155: static void TempMoveDraft()
                    156: {
                    157:     char *ptr;
                    158:     if (FileExists(draftFile)) {
                    159:        do {
                    160:            ptr = MakeNewTempFileName();
                    161:            (void) strcpy(tempDraftFile, draftFile);
                    162:            (void) strcpy(rindex(tempDraftFile, '/'), rindex(ptr, '/'));
                    163:        } while (FileExists(tempDraftFile));
                    164:        RenameAndCheck(draftFile, tempDraftFile);
                    165:     }
                    166: }
                    167: 
                    168: 
                    169: 
                    170: /* Restore the draftfile from its temporary hiding place. */
                    171: 
                    172: static void RestoreDraft()
                    173: {
                    174:     if (*tempDraftFile) {
                    175:        RenameAndCheck(tempDraftFile, draftFile);
                    176:        *tempDraftFile = 0;
                    177:     }
                    178: }
                    179: 
                    180: 
                    181: 
                    182: /* Public routines */
                    183: 
                    184: 
                    185: /* Given a message, return the corresponding filename. */
                    186: 
                    187: char *MsgFileName(msg)
                    188: Msg msg;
                    189: {
                    190:     static char result[500];
                    191:     (void) sprintf(result, "%s/%d", msg->toc->path, msg->msgid);
                    192:     return result;
                    193: }
                    194: 
                    195: 
                    196: 
                    197: /* Save any changes to a message.  Also calls the toc routine to update the
                    198:    scanline for this msg. */
                    199: 
                    200: void MsgSaveChanges(msg)
                    201: Msg msg;
                    202: {
                    203:     if (msg->source) {
                    204:        XtEDiskSaveFile(msg->source);
                    205:        EnableProperButtons(msg->scrn);
                    206:        if (!msg->temporary)
                    207:            TocMsgChanged(msg->toc, msg);
                    208:     }
                    209: }
                    210: 
                    211: /*ARGSUSED*/
                    212: static Boolean IfMapWindow(dpy, event, scrn)
                    213: Display *dpy;
                    214: XEvent *event;
                    215: Scrn scrn;
                    216: {
                    217:     return (event->type == MapNotify && event->xany.window == scrn->window);
                    218: }
                    219: 
                    220: /* Associate the given message with the given scrn.  If a message is
                    221:    changed, and we are removing it from any scrn, then ask for confirmation
                    222:    first.  If the message is a temporary one and it is removed from any scrn,
                    223:    it is deleted. */
                    224: 
                    225: static int SetScrn(msg, scrn, force)
                    226: Msg msg;
                    227: Scrn scrn;
                    228: Boolean force; /* If TRUE, don't ask for confirm; just do it */
                    229: {
                    230:     char str[100];
                    231:     if (msg == NULL && scrn == NULL) return 0;
                    232:     if (scrn && scrn->msg != msg)
                    233:        if (SetScrn(scrn->msg, (Scrn) NULL, force))
                    234:            return DELETEABORTED;
                    235:     if (msg == NULL)
                    236:        return 0;
                    237:     if (msg->scrn == scrn) return 0;
                    238:     if (msg->scrn) {
                    239:        if (msg->source && scrn == NULL) {
                    240:            if (XtEDiskChanged(msg->source) && !force) {
                    241:                (void)sprintf(str,
                    242:                              "Are you sure you want to remove changes to %s?",
                    243:                              NameOfMsg(msg));
                    244:                if (!Confirm(msg->scrn, str)) return DELETEABORTED;
                    245:            }
                    246:            XtDestroyEDiskSource(msg->source);
                    247:            msg->source = NULL;
                    248:        }
                    249:        msg->scrn->msg = NULL;
                    250:        ResetMsgLabel(msg->scrn);
                    251:        RedisplayMsg(msg->scrn);
                    252:        EnableProperButtons(msg->scrn);
                    253:        if (msg->scrn->kind != STtocAndView)
                    254:            QXStoreName(theDisplay, msg->scrn->window, progName);
                    255:        msg->scrn = NULL;
                    256:        if (scrn == NULL) {
                    257:            if (msg->temporary) {
                    258:                (void) unlink(MsgFileName(msg));
                    259:                TocRemoveMsg(msg->toc, msg);
                    260:                MsgFree(msg);
                    261:            }           
                    262:            return 0;
                    263:        }
                    264:     }
                    265:     if (msg->source == NULL)
                    266:        msg->source = XtCreateEDiskSource(MsgFileName(msg), XttextRead);
                    267:     if (scrn->kind == STcomp) {
                    268:        XtEDiskChangeEditMode(msg->source, XttextEdit);
                    269:        if (defGrabFocus) {
                    270:            XEvent event;
                    271:            QXMapWindow(theDisplay, scrn->window);
                    272:            XPeekIfEvent(theDisplay, &event, IfMapWindow, (char *)scrn);
                    273:            QXSetInputFocus(theDisplay, scrn->viewwindow,
                    274:                            RevertToParent, CurrentTime);
                    275:        }
                    276:     }
                    277: 
                    278:     msg->scrn = scrn;
                    279:     scrn->msg = msg;
                    280:     ResetMsgLabel(msg->scrn);
                    281:     RedisplayMsg(msg->scrn);
                    282:     EnableProperButtons(msg->scrn);
                    283:     if (msg->scrn->kind != STtocAndView)
                    284:        QXStoreName(theDisplay, msg->scrn->window, NameOfMsg(msg));
                    285:     return 0;
                    286: }
                    287: 
                    288: 
                    289: /* Associate the given msg and scrn, asking for confirmation if necessary. */
                    290: 
                    291: int MsgSetScrn(msg, scrn)
                    292: Msg msg;
                    293: Scrn scrn;
                    294: {
                    295:     return SetScrn(msg, scrn, FALSE);
                    296: }
                    297: 
                    298: 
                    299: /* Same as above, but with the extra information that the message is actually
                    300:    a composition.  (Nothing currently takes advantage of that extra fact.) */
                    301: 
                    302: int MsgSetScrnForComp(msg, scrn)
                    303: Msg msg;
                    304: Scrn scrn;
                    305: {
                    306:     return SetScrn(msg, scrn, FALSE);
                    307: }
                    308: 
                    309: 
                    310: 
                    311: /* Associate the given msg and scrn, even if it means losing some unsaved
                    312:    changes. */
                    313: 
                    314: void MsgSetScrnForce(msg, scrn)
                    315: Msg msg;
                    316: Scrn scrn;
                    317: {
                    318:     (void) SetScrn(msg, scrn, TRUE);
                    319: }
                    320: 
                    321: 
                    322: 
                    323: /* Return what screen (if any) is displaying the given msg. */
                    324: 
                    325: Scrn MsgGetScrn(msg)
                    326: Msg msg;
                    327: {
                    328:     return msg->scrn;
                    329: }
                    330: 
                    331: 
                    332: 
                    333: /* Set the fate of the given message. */
                    334: 
                    335: void MsgSetFate(msg, fate, desttoc)
                    336:   Msg msg;
                    337:   FateType fate;
                    338:   Toc desttoc;
                    339: {
                    340:     Toc toc = msg->toc;
                    341:     XtTextBlock text;
                    342:     msg->fate = fate;
                    343:     msg->desttoc = desttoc;
                    344:     if (fate == Fignore && msg == msg->toc->curmsg)
                    345:        text.ptr = "+";
                    346:     else {
                    347:        switch (fate) {
                    348:            case Fignore:       text.ptr = " "; break;
                    349:            case Fcopy:         text.ptr = "C"; break;
                    350:            case Fmove:         text.ptr = "^"; break;
                    351:            case Fdelete:       text.ptr = "D"; break;
                    352:        }
                    353:     }
                    354:     text.length = 1;
                    355:     text.firstPos = msg->position + MARKPOS;
                    356:     if (toc->stopupdate)
                    357:        toc->needsrepaint = TRUE;
                    358:     if (toc->scrn && msg->visible && !toc->needsrepaint &&
                    359:            *text.ptr != msg->buf[MARKPOS])
                    360:        (void) XtTextReplace(DISPLAY toc->scrn->tocwindow,
                    361:                             msg->position + MARKPOS,
                    362:                             msg->position + MARKPOS + 1, &text);
                    363:     else
                    364:        msg->buf[MARKPOS] = *text.ptr;
                    365:     if (msg->scrn)
                    366:        ResetMsgLabel(msg->scrn);
                    367: }
                    368: 
                    369: 
                    370: 
                    371: /* Get the fate of this message. */
                    372: 
                    373: FateType MsgGetFate(msg, toc)
                    374: Msg msg;
                    375: Toc *toc;                      /* RETURN */
                    376: {
                    377:     if (toc) *toc = msg->desttoc;
                    378:     return msg->fate;
                    379: }
                    380: 
                    381: 
                    382: /* Make this a temporary message. */
                    383: 
                    384: void MsgSetTemporary(msg)
                    385: Msg msg;
                    386: {
                    387:     msg->temporary = TRUE;
                    388:     ResetMsgLabel(msg->scrn);
                    389: }
                    390: 
                    391: 
                    392: /* Make this a permanent message. */
                    393: 
                    394: void MsgSetPermanent(msg)
                    395: Msg msg;
                    396: {
                    397:     msg->temporary = FALSE;
                    398:     ResetMsgLabel(msg->scrn);
                    399: }
                    400: 
                    401: 
                    402: 
                    403: /* Return the id# of this message. */
                    404: 
                    405: int MsgGetId(msg)
                    406: Msg msg;
                    407: {
                    408:     return msg->msgid;
                    409: }
                    410: 
                    411: 
                    412: /* Return the scanline for this message. */
                    413: 
                    414: char *MsgGetScanLine(msg)
                    415: Msg msg;
                    416: {
                    417:     return msg->buf;
                    418: }
                    419: 
                    420: 
                    421: 
                    422: /* Return the toc this message is in. */
                    423: 
                    424: Toc MsgGetToc(msg)
                    425: Msg msg;
                    426: {
                    427:     return msg->toc;
                    428: }
                    429: 
                    430: 
                    431: /* Set the reapable flag for this msg. */
                    432: 
                    433: void MsgSetReapable(msg)
                    434: Msg msg;
                    435: {
                    436:     msg->reapable = TRUE;
                    437:     EnableProperButtons(msg->scrn);
                    438: }
                    439: 
                    440: 
                    441: 
                    442: /* Clear the reapable flag for this msg. */
                    443: 
                    444: void MsgClearReapable(msg)
                    445: Msg msg;
                    446: {
                    447:     msg->reapable = FALSE;
                    448:     EnableProperButtons(msg->scrn);
                    449: }
                    450: 
                    451: 
                    452: /* Get the reapable value for this msg.  Returns TRUE iff the reapable flag
                    453:    is set AND no changes have been made. */
                    454: 
                    455: int MsgGetReapable(msg)
                    456: Msg msg;
                    457: {
                    458:     return msg == NULL || (msg->reapable &&
                    459:                           (msg->source == NULL ||
                    460:                            !XtEDiskChanged(msg->source)));
                    461: }
                    462: 
                    463: 
                    464: /* Make it possible to edit the given msg. */
                    465: void MsgSetEditable(msg)
                    466: Msg msg;
                    467: {
                    468:     if (msg && msg->source) {
                    469:        XtEDiskChangeEditMode(msg->source, XttextEdit);
                    470:        if (defGrabFocus && msg->scrn)
                    471:            QXSetInputFocus(theDisplay, msg->scrn->viewwindow,
                    472:                            RevertToParent, CurrentTime);
                    473:        EnableProperButtons(msg->scrn);
                    474:     }
                    475: }
                    476: 
                    477: 
                    478: 
                    479: /* Turn off editing for the given msg. */
                    480: 
                    481: void MsgClearEditable(msg)
                    482: Msg msg;
                    483: {
                    484:     if (msg && msg->source) {
                    485:        XtEDiskChangeEditMode(msg->source, XttextRead);
                    486:        EnableProperButtons(msg->scrn);
                    487:     }
                    488: }
                    489: 
                    490: 
                    491: 
                    492: /* Get whether the msg is editable. */
                    493: 
                    494: int MsgGetEditable(msg)
                    495: Msg msg;
                    496: {
                    497:     return msg && msg->source &&
                    498:        (*msg->source->editType)(msg->source) == XttextEdit;
                    499: }
                    500: 
                    501: 
                    502: /* Get whether the msg has changed since last saved. */
                    503: 
                    504: int MsgChanged(msg)
                    505: Msg msg;
                    506: {
                    507:     return msg && msg->source && XtEDiskChanged(msg->source);
                    508: }
                    509: 
                    510: 
                    511: 
                    512: /* Call the given function when the msg changes. */
                    513: 
                    514: void MsgSetCallOnChange(msg, func, param)
                    515: Msg msg;
                    516: void (*func)();
                    517: caddr_t param;
                    518: {
                    519:     XtEDiskSetCallbackWhenChanged(msg->source, func, param);
                    520: }
                    521: 
                    522: 
                    523: 
                    524: /* Call no function when the msg changes. */
                    525: 
                    526: void MsgClearCallOnChange(msg)
                    527: Msg msg;
                    528: {
                    529:     XtEDiskSetCallbackWhenChanged(msg->source, NULL, (caddr_t) NULL);
                    530: }
                    531: 
                    532: 
                    533: /* Send (i.e., mail) the given message as is.  First break it up into lines,
                    534:    and copy it to a new file in the process.  The new file is one of 10
                    535:    possible draft files; we rotate amoung the 10 so that the user can have up
                    536:    to 10 messages being sent at once.  (Using a file in /tmp is a bad idea
                    537:    because these files never actually get deleted, but renamed with some
                    538:    prefix.  Also, these should stay in an area private to the user for
                    539:    security.) */
                    540: 
                    541: void MsgSend(msg)
                    542: Msg msg;
                    543: {
                    544:     FILEPTR from;
                    545:     FILEPTR to;
                    546:     int     p, c, l, inheader, sendwidth, sendbreakwidth;
                    547:     char   *ptr, *ptr2, **argv, str[100];
                    548:     static sendcount = -1;
                    549:     MsgSaveChanges(msg);
                    550:     from = FOpenAndCheck(MsgFileName(msg), "r");
                    551:     sendcount = (sendcount + 1) % 10;
                    552:     (void) sprintf(str, "%s%d", xmhDraftFile, sendcount);
                    553:     to = FOpenAndCheck(str, "w");
                    554:     sendwidth = defSendLineWidth;
                    555:     sendbreakwidth = defBreakSendLineWidth;
                    556:     inheader = TRUE;
                    557:     while (ptr = ReadLine(from)) {
                    558:        if (inheader) {
                    559:            if (strncmpIgnoringCase(ptr, "sendwidth:", 10) == 0) {
                    560:                if (atoi(ptr+10) > 0) sendwidth = atoi(ptr+10);
                    561:                continue;
                    562:            }
                    563:            if (strncmpIgnoringCase(ptr, "sendbreakwidth:", 15) == 0) {
                    564:                if (atoi(ptr+15) > 0) sendbreakwidth = atoi(ptr+15);
                    565:                continue;
                    566:            }
                    567:            for (l = 0, ptr2 = ptr ; *ptr2 && !l ; ptr2++)
                    568:                l = (*ptr2 != ' ' && *ptr2 != '\t' && *ptr != '-');
                    569:            if (l) {
                    570:                (void) fprintf(to, "%s\n", ptr);
                    571:                continue;
                    572:            }
                    573:            inheader = FALSE;
                    574:            if (sendbreakwidth < sendwidth) sendbreakwidth = sendwidth;
                    575:        }
                    576:        do {
                    577:            for (p = c = l = 0, ptr2 = ptr;
                    578:                 *ptr2 && c < sendbreakwidth;
                    579:                 p++, ptr2++) {
                    580:                 if (*ptr2 == ' ' && c < sendwidth)
                    581:                     l = p;
                    582:                 if (*ptr2 == '\t') {
                    583:                     if (c < sendwidth) l = p;
                    584:                     c += 8 - (c % 8);
                    585:                 }
                    586:                 else
                    587:                 c++;
                    588:             }
                    589:            if (c < sendbreakwidth) {
                    590:                (void) fprintf(to, "%s\n", ptr);
                    591:                *ptr = 0;
                    592:            }
                    593:            else
                    594:                if (l) {
                    595:                    ptr[l] = 0;
                    596:                    (void) fprintf(to, "%s\n", ptr);
                    597:                    ptr += l + 1;
                    598:                }
                    599:                else {
                    600:                    for (c = 0; c < sendwidth; ) {
                    601:                        if (*ptr == '\t') c += 8 - (c % 8);
                    602:                        else c++;
                    603:                        (void) fputc(*ptr++, to);
                    604:                    }
                    605:                    (void) fputc('\n', to);
                    606:                }
                    607:        } while (*ptr);
                    608:     }
                    609:     (void) myfclose(from);
                    610:     (void) myfclose(to);
                    611:     argv = MakeArgv(3);
                    612:     argv[0] = "send";
                    613:     argv[1] = "-push";
                    614:     argv[2] = str;
                    615:     DoCommand(argv, (char *) NULL, (char *) NULL);
                    616:     XtFree((char *) argv);
                    617: }
                    618: 
                    619: 
                    620: /* Make the msg into the form for a generic composition.  Set msg->startPos
                    621:    so that the text insertion point will be placed at the end of the first
                    622:    line (which is usually the "To:" field). */
                    623: 
                    624: void MsgLoadComposition(msg)
                    625: Msg msg;
                    626: {
                    627:     static char *blankcomp = NULL; /* Array containing comp template */
                    628:     static int compsize = 0;
                    629:     static XtTextPosition startPos;
                    630:     char *file, **argv;
                    631:     int fid;
                    632:     if (blankcomp == NULL) {
                    633:        file = MakeNewTempFileName();
                    634:        argv = MakeArgv(4);
                    635:        argv[0] = "comp";
                    636:        argv[1] = "-file";
                    637:        argv[2] = file;
                    638:        argv[3] = "-nowhatnowproc";
                    639:        DoCommand(argv, (char *) NULL, "/dev/null");
                    640:        XtFree((char *) argv);
                    641:        compsize = GetFileLength(file);
                    642:        blankcomp = XtMalloc((unsigned) compsize);
                    643:        fid = myopen(file, O_RDONLY, 0666);
                    644:        if (compsize != read(fid, blankcomp, compsize))
                    645:            Punt("Error reading in MsgLoadComposition!");
                    646:        (void) myclose(fid);
                    647:        DeleteFileAndCheck(file);
                    648:        startPos = index(blankcomp, '\n') - blankcomp;
                    649:     }
                    650:     fid = myopen(MsgFileName(msg), O_WRONLY | O_TRUNC | O_CREAT, 0666);
                    651:     if (compsize != write(fid, blankcomp, compsize))
                    652:        Punt("Error writing in MsgLoadComposition!");
                    653:     (void) myclose(fid);
                    654:     TocSetCacheValid(msg->toc);
                    655:     msg->startPos = startPos;
                    656: }
                    657: 
                    658: 
                    659: 
                    660: /* Load a msg with a template of a reply to frommsg.  Set msg->startPos so
                    661:    that the text insertion point will be placed at the beginning of the
                    662:    message body. */
                    663: 
                    664: void MsgLoadReply(msg, frommsg)
                    665: Msg msg, frommsg;
                    666: {
                    667:     char **argv;
                    668:     char str1[100], str2[10];
                    669:     TempMoveDraft();
                    670:     argv = MakeArgv(4);
                    671:     argv[0] = "repl";
                    672:     (void) sprintf(str1, "+%s", frommsg->toc->foldername);
                    673:     argv[1] = str1;
                    674:     (void) sprintf(str2, "%d", frommsg->msgid);
                    675:     argv[2] = str2;
                    676:     argv[3] = "-nowhatnowproc";
                    677:     DoCommand(argv, (char *) NULL, "/dev/null");
                    678:     RenameAndCheck(draftFile, MsgFileName(msg));
                    679:     RestoreDraft();
                    680:     TocSetCacheValid(frommsg->toc); /* If -anno is set, this keeps us from
                    681:                                       rescanning folder. */
                    682:     TocSetCacheValid(msg->toc);
                    683:     msg->startPos = GetFileLength(MsgFileName(msg));
                    684: }
                    685: 
                    686: 
                    687: 
                    688: /* Load a msg with a template of forwarding a list of messages.  Set 
                    689:    msg->startPos so that the text insertion point will be placed at the end
                    690:    of the first line (which is usually a "To:" field). */
                    691: 
                    692: void MsgLoadForward(msg, mlist)
                    693:   Msg msg;
                    694:   MsgList mlist;
                    695: {
                    696:     char  **argv, str[100];
                    697:     int     i;
                    698:     TempMoveDraft();
                    699:     argv = MakeArgv(3 + mlist->nummsgs);
                    700:     argv[0] = "forw";
                    701:     (void) sprintf(str, "+%s", mlist->msglist[0]->toc->foldername);
                    702:     argv[1] = MallocACopy(str);
                    703:     for (i = 0; i < mlist->nummsgs; i++) {
                    704:         (void) sprintf(str, "%d", mlist->msglist[i]->msgid);
                    705:         argv[2 + i] = MallocACopy(str);
                    706:     }
                    707:     argv[2 + i] = "-nowhatnowproc";
                    708:     DoCommand(argv, (char *) NULL, "/dev/null");
                    709:     for (i = 1; i < 2 + mlist->nummsgs; i++)
                    710:         XtFree((char *) argv[i]);
                    711:     XtFree((char *) argv);
                    712:     RenameAndCheck(draftFile, MsgFileName(msg));
                    713:     RestoreDraft();
                    714:     TocSetCacheValid(msg->toc);
                    715:     msg->source = XtCreateEDiskSource(MsgFileName(msg), XttextEdit);
                    716:     msg->startPos = (*msg->source->scan)(msg->source, 0, XtstEOL, XtsdRight,
                    717:                                         1, FALSE);
                    718: }
                    719: 
                    720: 
                    721: /* Load msg with a copy of frommsg. */
                    722: 
                    723: void MsgLoadCopy(msg, frommsg)
                    724: Msg msg, frommsg;
                    725: {
                    726:     char str[500];
                    727:     (void)strcpy(str, MsgFileName(msg));
                    728:     CopyFileAndCheck(MsgFileName(frommsg), str);
                    729:     TocSetCacheValid(msg->toc);
                    730: }
                    731: 
                    732: 
                    733: 
                    734: /* Checkpoint the given message. */
                    735: 
                    736: void MsgCheckPoint(msg)
                    737: Msg msg;
                    738: {
                    739:     if (msg && msg->source) {
                    740:        XtEDiskMakeCheckpoint(msg->source);
                    741:        TocSetCacheValid(msg->toc);
                    742:     }
                    743: }
                    744: 
                    745: 
                    746: /* Free the storage being used by the given msg. */
                    747: 
                    748: void MsgFree(msg)
                    749: Msg msg;
                    750: {
                    751:     XtFree(msg->buf);
                    752:     XtFree((char *)msg);
                    753: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.