home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / amiga / comms / network / grn1src.lha / system.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-04  |  28.5 KB  |  939 lines

  1. #include        "defs.h"
  2. #include        "headers.h"
  3.  
  4. #include        <stdarg.h>
  5. #include        <sys/types.h>
  6. #include        <sys/stat.h>
  7.  
  8. #ifdef LATTICE
  9. #ifndef __SASC
  10. #define __SASC
  11. #endif
  12. #endif
  13.  
  14. #ifdef __SASC
  15. #include <sys/types.h>
  16. #endif
  17.  
  18. // #define PROCDEBUG
  19.  
  20. #ifdef PROCDEBUG
  21. #define D(x)    printf x
  22. #else
  23. #define D(x)
  24. #endif
  25.  
  26. //      EXPORTS
  27.  
  28. void    CloseLibs (LIBDEFS libDefs[]);
  29. void    OpenLibs (LIBDEFS libDefs[]);
  30. GADGET  *CreateGadgets(GADGET *gadArray[], GADDEF gadDefs[]);
  31. short   TextLen (RPORT *rp, char *txt);
  32. void    InitSystem (void);
  33. void    CloseSystem (void);
  34. WINDOW *CreateWindow(GADGET *gList, short left, short top, short width,
  35.                                     short height, char *title);
  36. void    DefaultIDCMPFunc (WINDOW *window, IMSG *m);
  37. int     OutputStrings (const int fd, const char *str, ...);
  38. int     Editor (const char *filename, const char *editor);
  39. char   *TempName (void);
  40. int     CopyStrings (char *dest, const char *str, ...);
  41. char   *itoa (const long i);
  42. void    PostNews (const int followupFlag, const char *filename);
  43. void    SendMail (const char *filename);
  44.  
  45. char    prefFontName [128] = "grn.font";         // name of preference font (defaults to grn.font)
  46. UWORD   prefFontSize = 8;                       // defaults to 8
  47. UWORD   prefWidth = 640, prefHeight = 400;      // 640x400 or whatever is in tooltypes
  48. UWORD   prefTop = 0, prefLeft = 0;              // defaults to top right edge of screen!
  49.  
  50. /*
  51.  * List of libraries used
  52.  */
  53. IBASE   *IntuitionBase = 0;
  54. LIBRARY *GfxBase = 0;
  55. LIBRARY *DiskfontBase = 0;
  56. LIBRARY *AslBase = 0;
  57. LIBRARY *GadToolsBase = 0;
  58. LIBRARY *WorkbenchBase = 0;
  59. LIBRARY *IconBase = 0;
  60. LIBRARY *CxBase = 0;
  61.  
  62. /*
  63.  * Array of library names/base pointers.  To open an additional library, define
  64.  * the base above and add a line here.
  65.  */
  66. LIBDEFS libDefs[] = {
  67.         "intuition.library",   (APTR *) &IntuitionBase,
  68.         "graphics.library",    (APTR *) &GfxBase,
  69.         "diskfont.library",    (APTR *) &DiskfontBase,
  70.         "asl.library",         (APTR *) &AslBase,
  71.         "gadtools.library",    (APTR *) &GadToolsBase,
  72.         "workbench.library",   (APTR *) &WorkbenchBase,
  73.         "icon.library",        (APTR *) &IconBase,
  74.         "commodities.library", (APTR *) &CxBase,
  75.         0, 0
  76. };
  77.  
  78. /*
  79.  * Global variables
  80.  */
  81. VINFO   *vi = 0;
  82. SCREEN  *screen = 0;
  83. VPORT   *vp;
  84. RPORT   *rp;
  85.  
  86. RPORT   topazRastPort, *topazRP = &topazRastPort;
  87.  
  88. BOOL    customScreenFlag = 0;
  89.  
  90. /*
  91.  * This text attribute is the default text attribute used for various
  92.  * features.  It should be openable via OpenFont(), which implies an
  93.  * OpenDiskFont() call to load it into memory.  In this case, defaultFontAttr
  94.  * is a ROM font, so I don't bother.  BEWARE if you choose another !!!
  95.  */
  96. TATTR   topaz80 = { "topaz.font", 8, 0, 0 };
  97. TATTR   defaultFontAttr = { "grn.font", 8, 0, 0 };
  98. FONT    *defaultFont = 0, *topaz80Font = 0;
  99.  
  100. /*
  101.  * Without this look3D array passed to the OpenScreenTags() call, you
  102.  * don't get the 3D effect.  Why this isn't the default, only CBM knows :)
  103.  */
  104. UWORD   look3D[] = { ~0, };
  105.  
  106. /*
  107.  * This rect structure contains the overscan info for what size the screen
  108.  * should be!
  109.  */
  110. RECT    oscanRect;
  111. short   screenWidth, screenHeight;      /* computed width and height of screen */
  112. short   screenTop;                      /* computed below title bar */
  113.  
  114. /************************************************************************/
  115.  
  116. /*
  117.  * These might be the shortest open/close library routines ever :)
  118.  */
  119. void    CloseLibs (LIBDEFS libDefs[])
  120. {
  121.         short   i;
  122.  
  123.         for (i = 0; libDefs [i+1].name; i++)
  124.                 ;
  125.         while (i >= 0) {
  126.                 if (*libDefs [i].base)
  127.                         CloseLibrary ((LIBRARY *)*libDefs [i].base);
  128.                 *libDefs [i--].base = 0;
  129.         }
  130.         return;
  131. }
  132.  
  133. void    OpenLibs (LIBDEFS libDefs[])
  134. {
  135.         short   i;
  136.  
  137.         for (i = 0; libDefs [i].name; i++) {
  138.                 *libDefs [i].base = (APTR) OpenLibrary (libDefs [i].name, 0);
  139.                 panic0 (*libDefs [i].base, "Can't open %s", libDefs [i].name);
  140.         }
  141.         return;
  142. }
  143.  
  144. /************************************************************************/
  145.  
  146. /*
  147.  * gadgetList = CreateGadgets(gadDefs);
  148.  * GADGET       *gadgetList;            list of created gadgets
  149.  * GADDEF       gadDefs[];              array of gadget initializations
  150.  *
  151.  * Synopsis:
  152.  *      Pass in a gadDefs, and you get an initialized list of gadgets,
  153.  *      suitable for linking to a window for GadTools.
  154.  */
  155. GADGET  *CreateGadgets (GADGET *gadArray[], GADDEF gadDefs[])
  156. {
  157.         GADGET  *gadget, *glist = 0;
  158.         int     i;
  159.         int     kind;
  160.         NEWGAD  ng;
  161.  
  162.         gadget = CreateContext (&glist);
  163.         panic0 (gadget, "Can't CreateContext");
  164.         for (i = 0; gadDefs [i].tags; i++) {
  165.                 if ((kind = gadDefs [i].kind) != LISTVIEW_KIND)
  166.                         ng.ng_TextAttr = &topaz80;
  167.                 else
  168.                         ng.ng_TextAttr = &defaultFontAttr;
  169.                 ng.ng_GadgetID   = i;
  170.                 ng.ng_VisualInfo = vi;
  171.                 ng.ng_LeftEdge   = gadDefs [i].left;
  172.                 ng.ng_TopEdge    = gadDefs [i].top;
  173.                 ng.ng_Width      = gadDefs [i].width;
  174.                 ng.ng_Height     = gadDefs [i].height;
  175.                 ng.ng_GadgetText = gadDefs [i].text;
  176.                 ng.ng_Flags      = gadDefs [i].flags;
  177.                 gadget = CreateGadgetA (kind, gadget, &ng, gadDefs [i].tags);
  178.                 gadArray [i] = gadget;
  179.                 panic0 (gadget, "Can't CreateGadget");
  180.         }
  181.         return glist;
  182. }
  183.  
  184. /************************************************************************/
  185.  
  186. short   TextLen (RPORT *rp, char *txt)
  187. {
  188.         if (!rp)
  189.                 return 0;
  190.  
  191.         return TextLength (rp, txt, strlen (txt));
  192. }
  193.  
  194. static int
  195. _swrite (char *buf, size_t n1, size_t n2, char **sst)
  196. {
  197.     size_t n;
  198.  
  199.     if (n1 == 1)
  200.         n = n2;
  201.     else if (n2 == 1)
  202.         n = n1;
  203.     else
  204.         n = n1 * n2;
  205.  
  206. #ifdef __SASC
  207.     memcpy (*sst, buf, n);
  208. #else
  209.     _slow_bcopy (buf, *sst, n);
  210. #endif
  211.     *sst += n;
  212.  
  213.     return (int) n2;
  214. }
  215.  
  216. /*
  217.  * void t_printf(fmt, ...);
  218.  * char         *fmt;
  219.  *
  220.  * Synopsis:
  221.  *      Similar to printf, except the results end up at the end of the
  222.  *      "event" listview.  Only 4 args supported to printf...
  223.  */
  224. #ifdef __SASC
  225. void    t_printf (WINDOW *win, const char *fmt, long arg1, long arg2, long arg3, long arg4) {
  226. #else
  227. void    t_printf (WINDOW *win, const char *fmt, ...) {
  228. #endif
  229.         static char     buf [128];
  230.         extern WINDOW   *mainWindow;
  231.         char            *ptr = buf;
  232.         va_list         va;
  233.  
  234.         if (!win)
  235.                 return;  // so it's safe to call us from a batch routine
  236. #ifdef __SASC
  237.         sprintf (buf, fmt, arg1, arg2, arg3, arg4);
  238. #else
  239.         // DICE or GCC
  240.         va_start (va, fmt);
  241.         _pfmt (fmt, va, _swrite, &ptr);
  242.         *ptr = 0;
  243. #endif
  244.         SetWindowTitles (win, buf, GRN_VERSION);
  245.         va_end (va);
  246.         return;
  247. }
  248.  
  249. /************************************************************************/
  250.  
  251. /*
  252.  * void GadgetUp(m);
  253.  * IMSG *m;             ptr to IntuiMessage received
  254.  *
  255.  * Synopsis:
  256.  *      Handles Gadtools/Intuition GADGETUP events.  For 2.0 and GadTools, the TAB and HELP
  257.  *      keys are special.  This routine handles these events, also.
  258.  *
  259.  * NOTES:
  260.  *      STRINGA_ExitHelp is not defined in any of the headers I got with SAS 5.10a, so the
  261.  *      HELP feature doesn't work.
  262.  */
  263. static void     GadgetUp(void (*func)(), IMSG *m)
  264. {
  265.         GADGET  *gad = (GADGET *)m->IAddress;
  266.  
  267.         (*func)(gad->GadgetID, m->Code);
  268. }
  269.  
  270. /*
  271.  * void GadgetDown(m);
  272.  * IMSG *m;             ptr to IntuiMessage received
  273.  *
  274.  * Synopsis:
  275.  *      Handles Gadtools/Intuition GADGETDOWN events.
  276.  */
  277. static void     GadgetDown(void (*func)(), IMSG *m)
  278. {
  279.         GADGET  *gad = (GADGET *)m->IAddress;
  280.  
  281.         (*func)(gad->GadgetID, m->Code);
  282. }
  283.  
  284. /*
  285.  * void MouseMove(m);
  286.  * IMSG *m;             ptr to IntuiMessage received
  287.  *
  288.  * Synopsis:
  289.  *      Handles Gadtools/Intuition MOUSEMOVE events.
  290.  */
  291. static void     MouseMove(void (*func)(), IMSG *m)
  292. {
  293.         GADGET  *gad = (GADGET *)m->IAddress;
  294.  
  295.         (*func)(gad->GadgetID, m->Code);
  296. }
  297.  
  298. /************************************************************************/
  299.  
  300. void    InitSystem (void)
  301. {
  302.         ULONG   modeID;
  303.         extern int update_only_mode;
  304.  
  305.         OpenLibs (libDefs);
  306.  
  307.         if (update_only_mode)
  308.                 // don't need any of this
  309.                 return;
  310.  
  311.         defaultFontAttr.ta_Name = (STRPTR) prefFontName;
  312.         defaultFontAttr.ta_YSize = prefFontSize;
  313.  
  314.         defaultFont = OpenDiskFont (&defaultFontAttr);
  315.         panic0 (defaultFont, "Can't OpenDiskFont(%s)", prefFontName);
  316.         topaz80Font = OpenDiskFont (&topaz80);
  317.         panic0 (topaz80Font, "Can't open topaz80 font");
  318.         InitRastPort (topazRP);
  319.         SetFont (topazRP, topaz80Font);
  320.  
  321. #ifdef MYKE_REMOVED_THIS
  322.         From Peter Cherna!
  323.  
  324.         if ( wbscreen = LockPubScreen("Workbench") )
  325.         {
  326.             if ( ( modeID = GetVPModeID( &wbscreen->ViewPort ) ) != INVALID_ID )
  327.             {
  328.                 if ( QueryOverscan( modeID, &rect, OSCAN_TEXT ) )
  329.                 {
  330.                    /* got it */
  331.                 }
  332.             }
  333.             UnlockPubScreen( NULL, wbscreen );
  334.         }
  335. #endif
  336.  
  337.         screen = LockPubScreen(NULL);
  338.         panic0(screen, "Can't lockpubscreen");
  339.         if ((modeID = GetVPModeID( &screen->ViewPort)) == INVALID_ID) panic("Can'g GetVPModeID()");
  340.         panic0 (QueryOverscan (modeID, &oscanRect, OSCAN_TEXT), "Can't QueryOverscan()");
  341.         screenWidth = (oscanRect.MaxX - oscanRect.MinX + 1);
  342.         screenHeight = (oscanRect.MaxY - oscanRect.MinY + 1);
  343.  
  344.         if (screenHeight < prefHeight || screenWidth < prefWidth) {
  345.                 UnlockPubScreen (NULL, screen);
  346.  
  347.                 modeID = (prefHeight < 400) ? HIRES_KEY : HIRESLACE_KEY;
  348.                 panic0 (QueryOverscan (modeID, &oscanRect, OSCAN_TEXT), "Can't QueryOverScan()");
  349.  
  350.                 screenWidth = (oscanRect.MaxX - oscanRect.MinX + 1);
  351.                 screenHeight = (oscanRect.MaxY - oscanRect.MinY + 1);
  352.                 screen = OpenScreenTags(NULL,
  353.                         SA_DClip, &oscanRect,
  354. #ifdef MYKE_REMOVED_THIS
  355.                         SA_SysFont, 1,
  356. #endif
  357.                         SA_Left,0,
  358.                         SA_Top,0,
  359.                         SA_Width,screenWidth,
  360.                         SA_Height,screenHeight,
  361.                         SA_Depth,2,
  362.                         SA_DetailPen,0,
  363.                         SA_BlockPen,1,
  364.                         SA_Title, GRN_VERSION,
  365.                         SA_ErrorCode,0,
  366. #ifdef MYKE_REMOVED_THIS
  367.                         SA_SysFont,0,
  368. #endif
  369.                         SA_Type,CUSTOMSCREEN,
  370.                         SA_ShowTitle,TRUE,
  371.                         SA_Pens,&look3D[0],
  372.                         SA_DisplayID,HIRESLACE_KEY,
  373.                         TAG_DONE
  374.                 );
  375.                 panic0 (screen, "Can't open screen");
  376.                 customScreenFlag = !0;
  377.         }
  378.  
  379.         screenTop = screen->BarHeight+1;
  380.         screenWidth = screen->Width;
  381.         screenHeight = screen->Height;
  382.  
  383.         rp = &screen->RastPort;
  384.         vp = &screen->ViewPort;
  385.         vi = GetVisualInfo (screen, TAG_DONE);
  386.         panic0 (vi, "Can't GetVisualInfo");
  387.         return;
  388. }
  389.  
  390.  
  391. void    CloseSystem (void)
  392. {
  393.         if (topaz80Font) {
  394.                 CloseFont (topaz80Font);
  395.                 topaz80Font = 0;
  396.         }
  397.         if (defaultFont) {
  398.                 CloseFont (defaultFont);
  399.                 defaultFont = 0;
  400.         }
  401.         if (screen) {
  402.                 if (customScreenFlag) {
  403.                         CloseScreen (screen);
  404.                 }
  405.                 else {
  406.                         UnlockPubScreen (NULL, screen);
  407.                 }
  408.                 screen = 0;
  409.         }
  410.         if (vi) {
  411.                 FreeVisualInfo (vi);
  412.                 vi = 0;
  413.         }
  414.         CloseLibs (libDefs);
  415.         return;
  416. }
  417.  
  418. WINDOW  *CreateWindow (GADGET *gList, short left, short top, short width, short height, char *title)
  419. {
  420.         WINDOW  *window;
  421.  
  422.         if (!top) top = screenTop+1;
  423.  
  424.         if (customScreenFlag) {
  425.                 window = OpenWindowTags(NULL,
  426.                         WA_Left,left,
  427.                         WA_Top,top,
  428.                         WA_Width,width,
  429.                         WA_Height,height,
  430.                         WA_DetailPen,0,
  431.                         WA_BlockPen,1,
  432.                         WA_IDCMP,MYIDCMP,
  433.                         WA_Gadgets,gList,
  434.                         WA_Title,0,
  435.                         WA_CustomScreen,screen,
  436.                         WA_SuperBitMap,0,
  437.                         WA_MinWidth,30,
  438.                         WA_MinHeight,30,
  439.                         WA_MaxWidth,-1,
  440.                         WA_MaxHeight,-1,
  441.                         WA_SizeGadget,FALSE,
  442.                         WA_DragBar,TRUE,
  443.                         WA_DepthGadget,TRUE,
  444.                         WA_CloseGadget,TRUE,
  445.                         WA_Backdrop,FALSE,
  446.                         WA_ReportMouse,FALSE,
  447.                         WA_Borderless,FALSE,
  448.                         WA_Activate,TRUE,
  449.                         WA_RMBTrap,FALSE,
  450.                         WA_SimpleRefresh,TRUE,
  451.                         TAG_DONE
  452.                 );
  453.         }
  454.         else {
  455.                 window = OpenWindowTags(NULL,
  456.                         WA_Left,left,
  457.                         WA_Top,top,
  458.                         WA_Width,width,
  459.                         WA_Height,height,
  460.                         WA_DetailPen,0,
  461.                         WA_BlockPen,1,
  462.                         WA_IDCMP,MYIDCMP,
  463.                         WA_Gadgets,gList,
  464.                         WA_Title,title,
  465.                         WA_SuperBitMap,0,
  466.                         WA_MinWidth,30,
  467.                         WA_MinHeight,30,
  468.                         WA_MaxWidth,-1,
  469.                         WA_MaxHeight,-1,
  470.                         WA_SizeGadget,FALSE,
  471.                         WA_DragBar,TRUE,
  472.                         WA_DepthGadget,TRUE,
  473.                         WA_CloseGadget,TRUE,
  474.                         WA_Backdrop,FALSE,
  475.                         WA_ReportMouse,FALSE,
  476.                         WA_Borderless,FALSE,
  477.                         WA_Activate,TRUE,
  478.                         WA_RMBTrap,FALSE,
  479.                         WA_SimpleRefresh,TRUE,
  480.                         TAG_DONE
  481.                 );
  482.         }
  483.         if (window)
  484.                 GT_RefreshWindow (window, NULL);
  485.         return window;
  486. }
  487.  
  488. void    DefaultIDCMPFunc (WINDOW *window, IMSG *m)
  489. {
  490.         t_printf (window, "Class = 0x%x Code = 0x%x", m->Class, m->Code);
  491.         return;
  492. }
  493.  
  494.  
  495. void    EventHandler(window, handleFunc, idcmpFunc, refreshFunc)
  496. WINDOW  *window;
  497. void    (*handleFunc)();
  498. void    (*idcmpFunc)();
  499. void    (*refreshFunc)();
  500. {
  501.         IMSG    *m, msg;
  502.  
  503.         while (m = GT_GetIMsg(window->UserPort)) {
  504.                 msg = *m;
  505.                 GT_ReplyIMsg(m);
  506.  
  507.                 switch (msg.Class) {
  508.                         case IDCMP_INTUITICKS:
  509.                                 break;
  510.  
  511.                         case IDCMP_MOUSEMOVE:
  512.                                 MouseMove (handleFunc, &msg);
  513.                                 break;
  514.  
  515.                         case IDCMP_GADGETUP:
  516.                                 GadgetUp (handleFunc, &msg);
  517.                                 break;
  518.  
  519.                         case IDCMP_GADGETDOWN:
  520.                                 GadgetDown (handleFunc, &msg);
  521.                                 break;
  522.  
  523.                         case IDCMP_REFRESHWINDOW:
  524.                                 GT_BeginRefresh (window);
  525.                                 if (refreshFunc)
  526.                                         (*refreshFunc)();
  527.                                 GT_EndRefresh (window, TRUE);
  528.                                 break;
  529.  
  530.                         default:
  531.                                 if (idcmpFunc)
  532.                                         (*idcmpFunc)(&msg);
  533.                                 else
  534.                                         DefaultIDCMPFunc (window, &msg);
  535.                                 break;
  536.                 }
  537.         }
  538.         return;
  539. }
  540.  
  541. /*      utility routines */
  542.  
  543. char *itoa (const long i)
  544. {
  545.         // itoa - integer to ascii
  546.  
  547.         static char buf [24];
  548.  
  549.         // FIXME - do this by hand to avoid sprintf() overhead
  550.         // D (("itoa(): enter, i = %d\n", i));
  551.  
  552.         sprintf (buf, "%d", i);
  553.  
  554.         // D (("itoa(): exit, buf = %s\n", buf));
  555.         return buf;
  556. }
  557.  
  558. int CopyStrings (char *dest, const char *str, ...)
  559. {
  560.     /*
  561.         Place all passed strings in dest, one after the other.
  562.  
  563.         You *MUST* NULL terminate the list of passed strings.
  564.         (it won't work on both DICE and SAS/C if you don't, not to mention GCC)
  565.     */
  566.  
  567.     va_list valist;
  568.     char *p;
  569.  
  570.     D (("CopyStrings(): enter\n"));
  571.     va_start (valist, str);
  572.  
  573.     *dest = '\0';
  574.     p = str;
  575.     while (p) {
  576.             strcat (dest, p);
  577.             p = va_arg (valist, char *);
  578.     }
  579.     va_end (valist);
  580.  
  581.     D (("CopyStrings(): exit, dest = '%s'\n", dest));
  582.     return 0;
  583. }
  584.  
  585. char *TempName (void)
  586. {
  587.         // TempName - generate a unique GRn-relevant temporary filename
  588.  
  589.         static int count = 0;
  590.         static char *buf = NULL;
  591.  
  592.         D (("TempName(): enter\n"));
  593.  
  594.         if (!buf) {
  595.                 buf = malloc (36);  // more than enough...
  596.  
  597.                 if (!buf) {
  598.                         D (("TempName(): exit, get mem failure\n"));
  599.                         return NULL;
  600.                 }
  601.         }
  602.  
  603.         CopyStrings (buf, "T:GRn", itoa ((long) FindTask (NULL)), ".", NULL);
  604.         // itoa() uses a static buffer. Using it twice in the
  605.         // CopyStrings() call would overwrite the first result.
  606.         strcat (buf, itoa (++count));
  607.  
  608.         D (("TempName(): exit, buf = %s\n", buf));
  609.         return buf;
  610. }
  611.  
  612. int Editor (const char *filename, const char *editor)
  613. {
  614.         // Editor - call the specified editor to edit the specified filename
  615.         //          if the Editor failed (non-zero return value), or the
  616.         //          user didn't change the input file, then let the user
  617.         //          know, and return an appropriate result.
  618.  
  619.         long rslt;
  620.         char buf [128];
  621.         struct stat s1, s2;
  622.  
  623.         D (("Editor(): enter, filename=%s, editor=%s\n", filename, editor));
  624.  
  625.         if (stat (filename, &s1) < 0) {
  626.                 t_printf (mainWindow, "Can't stat() %s", filename);
  627.  
  628.                 D (("Editor(): no stat 1, exit\n"));
  629.                 return 1;
  630.         }
  631.  
  632.         CopyStrings (buf, editor, " ", filename, NULL);
  633.  
  634.         rslt = System (buf, NULL);  // System() uses the PATH if any.
  635.         if (rslt == -1) {
  636.                 t_printf (mainWindow, "Can't execute your editor");
  637.  
  638.                 D (("Editor(): execute failure, exit\n"));
  639.                 return 1;
  640.         }
  641.  
  642.         if (rslt != 0) {
  643.                 CopyStrings (buf, "GRn - Your editor had a return code of ", itoa (rslt), NULL);
  644.                 if (TwoGadgetRequest (buf, "Send it anyway?",
  645.                                       "_Yes", "_No") == 0) {
  646.  
  647.                         D (("Editor(): bad status confirmed, exit\n"));
  648.                         return 1;
  649.                 }
  650.         }
  651.         if ((stat (filename, &s2) == 0) && s1.st_mtime == s2.st_mtime) {
  652.                 if (TwoGadgetRequest ("GRn - You didn't change the input file",
  653.                                       "Send it anyway?",
  654.                                       "_Yes", "_No") == 0) {
  655.  
  656.                         D (("Editor(): no changes cancel, exit\n"));
  657.                         return 1;
  658.                 }
  659.         }
  660.  
  661.         D (("Editor(): exit\n"));
  662.         return 0;
  663. }
  664.  
  665. int OutputStrings (const int fd, const char *str, ...)
  666. {
  667.     /*
  668.         Output all passed strings to fd via write().
  669.  
  670.         You *MUST* NULL terminate the list of passed strings.
  671.         (it won't work on both DICE and SAS/C if you don't, not to mention GCC)
  672.     */
  673.     // D (("OutputStrings(): enter\n"));
  674.     va_list valist;
  675.     char *p;
  676.  
  677.     va_start (valist, str);
  678.  
  679.     p = str;
  680.     while (p) {
  681.             write (fd, p, strlen (p));
  682.             p = va_arg (valist, char *);
  683.     }
  684.     va_end (valist);
  685.  
  686.     // D (("OutputStrings(): exit\n"));
  687.     return 0;
  688. }
  689.  
  690. void SendMail (const char *filename)
  691. {
  692.         /*
  693.                 SendMail() takes a completely built article residing in
  694.                 filename and goes through the required steps to inject
  695.                 the message into the mail system.
  696.         */
  697.  
  698.         // save filename -- it may be from TempName()
  699.         char
  700.                 temp [256],
  701.                 *fname = malloc (strlen (filename) + 1);
  702.         long
  703.                 rslt;
  704.  
  705.         D (("SendMail(): enter\n"));
  706.  
  707.         if (!fname) {
  708.                 t_printf (mainWindow, "Couldn't get memory for filename");
  709.  
  710.                 D (("SendMail(): get mem failure, exit\n"));
  711.                 return;
  712.         }
  713.         strcpy (fname, filename);
  714.  
  715.         if (Editor (fname, mailEditor)) {
  716.                 remove (fname);
  717.                 free (fname);
  718.  
  719.                 D (("SendMail(): Editor() goodbye, exit\n"));
  720.                 return;
  721.         }
  722.         if (!TwoGadgetRequest ("GRn - Mail Request",
  723.                                "   Send it off?   ",
  724.                                "_Yes", "_No")) {
  725.                 remove (fname);
  726.                 free (fname);
  727.  
  728.                 D (("SendMail(): don't send it, exit\n"));
  729.                 return;
  730.         }
  731.  
  732.         CopyStrings (temp, sendMail, " >nil: <", fname, " -f ", userName, NULL);
  733.  
  734.         rslt = SystemTags (temp, SYS_Input, 0,
  735.                                  SYS_Output, 0,
  736.                                  SYS_Asynch, 0,     // NP_Synchronous, 1,
  737.                                  NP_StackSize, 32000,
  738.                                  TAG_DONE);
  739.         if (rslt != 0) {
  740.                 CopyStrings (temp, "GRn - Your SendMail had a return value of ", itoa (rslt), NULL);
  741.                 OneGadgetRequest (temp,
  742.                                   "It may not have been completely posted",
  743.                                   "_Continue");
  744.         }
  745.         remove (fname);
  746.         free (fname);
  747.  
  748.         D (("SendMail(): exit\n"));
  749.         return;
  750. }
  751.  
  752. void PostNews (const int followupFlag, const char *filename)
  753. {
  754.         /*
  755.                 PostNews() takes a completely built article and goes
  756.                 through the machinations required to submit it to
  757.                 the news system.
  758.  
  759.                 It builds the references file, if needed.
  760.         */
  761.  
  762.         // I require that References and Message_ID be valid when followupFlag
  763.         // is set -- that is, they were NULL'ed and then ScanAndLoadHeaders
  764.         // was called. Results are unpredictable if this isn't true.
  765.  
  766.         // save filename -- it may be from TempName()
  767.  
  768.         char
  769.                 *fname = malloc (strlen (filename) + 1);
  770.         char
  771.                 temp [256],
  772.                 work [256];
  773.         char
  774.                 *ptr;               // temporary filename
  775.         long
  776.                 len,                // input read length
  777.                 rslt;               // result from System()
  778.         int
  779.                 fd,                 // user specified header information
  780.                 outfd;              // output article being built
  781.  
  782.         D (("PostNews(): enter\n"));
  783.  
  784.         if (!fname) {
  785.                 t_printf (mainWindow, "Can't get memory for filename");
  786.  
  787.                 D (("PostNews(): get mem failure, exit\n"));
  788.                 return;
  789.         }
  790.         strcpy (fname, filename);
  791.  
  792.         // followupFlag == -1 indicates this is an article from Publish().
  793.         // The user isn't allowed to edit those articles, and the verification
  794.         // for submission has already been given.
  795.  
  796.         if (followupFlag != -1) {
  797.  
  798.                 if (Editor (fname, newsEditor)) {
  799.                         remove (fname);
  800.                         free (fname);
  801.  
  802.                         D (("PostNews(): Editor() goodbye, exit\n"));
  803.                         return;
  804.                 }
  805.                 if (SendItRequest () == 0) {
  806.                         remove (fname);
  807.                         free (fname);
  808.  
  809.                         D (("PostNews(): SendItRequest() goodbye, exit\n"));
  810.                         return;
  811.                 }
  812.         }
  813.  
  814.         ptr = TempName ();
  815.         outfd = creat (ptr, 0660);
  816.         // we don't consider a failure on the above creat() to be
  817.         // significant enough to stop the Posting process, since
  818.         // "References:" is not a required field.
  819.         if ((followupFlag > 0) && (outfd >= 0) && Message_ID && References) {
  820.                 OutputStrings (outfd, "References: ",
  821.                         References ? References : "",
  822.                         " ",
  823.                         Message_ID ? Message_ID : "",
  824.                         "\n",
  825.                         NULL);
  826.  
  827.         }
  828.  
  829.         if (outfd >= 0) {
  830.                 // append user.nrefs to the refs (header) file
  831.                 strcpy (temp, uulib);
  832.                 CopyStrings (work, userName, ".nrefs", NULL);
  833.                 AddPart (temp, work, 256);
  834.                 fd = open (temp, O_RDONLY);
  835.                 if (fd < 0) {
  836.                         // try Dillon's naming convention (DMail and DNews)
  837.                         strcpy (temp, uulib);
  838.                         CopyStrings (work, userName, ".header", NULL);
  839.                         AddPart (temp, work, 256);
  840.                         fd = open (temp, O_RDONLY);
  841.                 }
  842.                 if (fd >= 0) {
  843.                         while ((len = read (fd, temp, 256)) > 0)
  844.                                 write (outfd, temp, len);
  845.                         close (fd);
  846.                 }
  847.  
  848.                 OutputStrings (outfd, "X-NewsSoftware: ", GRN_VERSION, "\n", NULL);
  849.                 close (outfd);
  850.  
  851.                 // kick postNews off with the special Refs option
  852.                 // postnews t:file -R t:ref-file -x t:file -x t:ref-file
  853.                 CopyStrings (temp, postNews, " ", fname, " -R ", ptr,
  854.                              " -x ", fname, " -x ", ptr, NULL);
  855.         }
  856.         else {
  857.                 // kick postNews off normally if no Refs file
  858.                 // postnews t:file -x t:file
  859.  
  860.                 CopyStrings (temp, postNews, " ", fname, " -x ", fname, NULL);
  861.         }
  862.         rslt = SystemTags (temp, SYS_Input, 0,
  863.                                  SYS_Output, 0,
  864.                                  SYS_Asynch, 1,     // NP_Synchronous, 0,
  865.                                  NP_StackSize, 32000,
  866.                                  TAG_DONE);
  867.         if (rslt) {
  868.                 if (rslt == -1) {
  869.                         // Special return from System(). The program didn't
  870.                         // run. Probably lack of memory.
  871.                         CopyStrings (temp, "Try again later (file=", fname,
  872.                                            ")", NULL);
  873.                         OneGadgetRequest ("GRn - Your PostNews failed",
  874.                                           temp,
  875.                                           "_Continue");
  876.                 }
  877.                 else {
  878.                         CopyStrings (temp, "GRn - Your PostNews had a return value of ",
  879.                                            itoa (rslt), NULL);
  880.                         OneGadgetRequest (temp,
  881.                                           "It may not have been completely posted",
  882.                                           "_Continue");
  883.                 }
  884.         }
  885.         free (fname);
  886.  
  887.         D (("PostNews(): exit\n"));
  888.         return;
  889. }
  890.  
  891. void ApplyMailHeaders (int outfd)
  892. {
  893.         char
  894.                 work [256],
  895.                 temp [256];
  896.         int
  897.                 i,
  898.                 rfd,
  899.                 rslt;
  900.  
  901.         D (("ApplyMailHeaders(): enter\n"));
  902.  
  903.         // Check for user specified mail headers and apply if found
  904.         strcpy (temp, uulib);
  905.         CopyStrings (work, userName, ".mrefs", NULL); // .mrefs for mail, .nrefs for news
  906.         AddPart (temp, work, 256);
  907.         if ((rfd = open (temp, O_RDONLY)) < 0) {
  908.                 // try DMail/DNews naming convention of "user.header"
  909.                 strcpy (temp, uulib);
  910.                 CopyStrings (work, userName, ".header", NULL);
  911.                 AddPart (temp, work, 256);
  912.  
  913.                 rfd = open (temp, O_RDONLY);
  914.         }
  915.  
  916.         i = 0;
  917.         if (rfd >= 0) {
  918.                 while ((rslt = read (rfd, work, 256)) > 0) {
  919.                         write (outfd, work, rslt);
  920.                         i = rslt;   // save last bufferlength
  921.                 }
  922.                 close (rfd);
  923.         }
  924.  
  925.         temp [0] = '\n';
  926.  
  927.         // that damn file should end with a newline, but we need to make sure
  928.         if (i && (work [i - 1] != '\n')) {
  929.                 // idiot
  930.                 write (outfd, temp, 1);
  931.         }
  932.  
  933.         // write the "empty line" to separate the body from the headers
  934.         write (outfd, temp, 1);
  935.  
  936.         D (("ApplyMailHeaders(): exit\n"));
  937.         return;
  938. }
  939.