home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / os2 / thread / pmnews.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-13  |  54.2 KB  |  1,845 lines

  1. /*
  2.     PMNEWS 1.0
  3.  
  4.     pmnews - a simple threaded news reader for PM
  5.  
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License, version 1, as
  9.     published by the Free Software Foundation.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     See the file COPYING, which contains a copy of the GNU General
  17.     Public License.
  18.  
  19.  
  20.     Compiled with IBM CSET/2.
  21.     Organized(?) in the Pascal fashion (main on bottom).
  22.  
  23.  */
  24.  
  25. #define INCL_DOSSEMAPHORES
  26. #define INCL_WIN
  27. #define INCL_WINERRORS
  28. #define INCL_GPI
  29.  
  30. #include <os2.h>                        /* PM header file               */
  31.  
  32. #include "defs.h"
  33. #include "pmnews.h"
  34.  
  35.  
  36. #define DO_UTIL( thing )  \
  37.         if ( util_func == TASK_FREE ) { \
  38.            util_func = thing; DosPostEventSem( work_to_do ); }
  39.  
  40. int  util_thread;    /* tid of utility task */
  41.  
  42. enum { TASK_FREE, MAIL, REPART, POST_EDIT, PRINT, SEARCH, SAVED, EOJ
  43.        } util_func = TASK_FREE;
  44.  
  45. INFO my_stuff;                          /* SNEWS .rc data */
  46.  
  47. HINI init;                              /* .ini handle */
  48. HAB  hab;                               /* PM anchor block handle       */
  49. HWND hwndFrame=0L;                      /* Frame window handle          */
  50. HWND hwndLbox=0L;                       /* group window handle          */
  51. HWND hwndNextA=0L;                      /* next article button */
  52. HWND hwndNextU=0L;                      /* next unread button */
  53. HWND hwndRetHdr=0L;                     /* return to hdrs button */
  54. HWND hwndNextAr=0L;                     /* next article */
  55. HWND hwndNextUr=0L;                     /* next unread  */
  56. ACTIVE  *gp;                            /* current group */
  57.  
  58. ALII *nicks;                            /* mailing aliases */
  59. CHAR *szString;                         /* procedure.                   */
  60.  
  61. PSZ  pszErrMsg;
  62. #define MSGBOXID    1001
  63.  
  64. static struct {
  65.    USHORT artwidth;     /* dimensions of article window */
  66.    USHORT artheight;
  67.    USHORT artx, arty;  /* article window location */
  68.    USHORT grpx, grpy;  /* group window location */
  69.    USHORT thrx, thry;  /* thread window location */
  70.    } artloc = { ARTWIDTH, ARTHEIGHT, ARTX, ARTY };
  71.  
  72. static char  savepath[80];   /* where to save article */
  73.  
  74. /*------------------- external routines -------------------------------*/
  75. char *make_news_group_name(char *ng);
  76.  
  77.  
  78. /*------------------- log PM error code to pmnews.err -----------------*/
  79. VOID logWinErr( VOID )
  80.   {
  81.   USHORT sev, id;
  82.   ERRORID ecode;
  83.  
  84.  
  85.   ecode = WinGetLastError( hab );
  86.   id = ERRORIDERROR( ecode );
  87.   sev  = ERRORIDSEV( ecode );
  88.   fprintf( errf, "PM Window error %x severity %x  \n", id, sev );
  89.   }
  90.  
  91.  
  92. /*-------------------- issue message box ------------------------------*/
  93. USHORT message( PSZ text, PSZ label, ULONG mstyle )
  94. {
  95.    USHORT tmpret;
  96.  
  97.    tmpret =
  98.    WinMessageBox(HWND_DESKTOP,         /* Parent window is desk top */
  99.                  hwndFrame,            /* Owner window is our frame */
  100.                  text,                 /* PMWIN Error message       */
  101.                  label,                /* Title bar message         */
  102.                  MSGBOXID,             /* Message identifier        */
  103.                  MB_MOVEABLE | MB_CUACRITICAL | mstyle ); /* Flags */
  104.    if (tmpret == MBID_ERROR)
  105.       logWinErr();
  106.    return tmpret;
  107. }
  108.  
  109.  
  110. /*----------------------------Abort Snews -----------------------------*/
  111. VOID AbortSN( HWND hwndFrame, HWND hwndClient, UINT errn  )
  112. {
  113. PERRINFO  pErrInfoBlk;
  114. PSZ       pszOffSet;
  115.  
  116.       DosBeep(100,10);
  117.  
  118.       fprintf( errf, "PMNews error %d \n", errn );
  119.       fclose (errf );
  120.  
  121.       if ((pErrInfoBlk = WinGetErrorInfo(hab)) != (PERRINFO)NULL)
  122.          {
  123.          pszOffSet = ((PSZ)pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
  124.          pszErrMsg = ((PSZ)pErrInfoBlk) + *((PSHORT)pszOffSet);
  125.          if((INT)hwndFrame && (INT)hwndClient)
  126.             message( (PSZ)pszErrMsg, "PMNews Error", MB_CANCEL );
  127.          WinFreeErrorInfo(pErrInfoBlk);
  128.          }
  129.       WinPostMsg(hwndClient, WM_QUIT, (MPARAM)0, (MPARAM)0);
  130.  
  131. } /* End of AbortSN */
  132.  
  133.  
  134. /* log the last PM error */
  135.  
  136.  
  137. /************* open the Article Window  ****************/
  138. HWND    open_art_win( PHWND pClient, PSZ title )
  139. {
  140.  
  141. static ULONG   ArtFlags;                /* Window creation control flags*/
  142. static char    title_bar[68];
  143.  
  144. HWND whwnd;
  145. int  rem, ix;
  146.  
  147.  
  148.   ArtFlags = FCF_TITLEBAR      | FCF_SYSMENU  |
  149.              FCF_SIZEBORDER    | FCF_MINMAX   |
  150.              FCF_TASKLIST |
  151.              FCF_VERTSCROLL    | FCF_MENU;
  152.  
  153.   strncpy( title_bar, title, 40 );
  154.   title_bar[40] = '\0';
  155.  
  156.   if ( ( tx != NULL ) && ( tx->rname != NULL ) )
  157.      {
  158.      rem = sizeof(title_bar) - strlen(title) - strlen(tx->rname);
  159.      if ( rem > 0 )
  160.         {
  161.         for ( ix = strlen(title_bar); ix < rem-2; ix++ ) title_bar[ix] = ' ';
  162.         title_bar[ix] = '\0';
  163.         strcat( title_bar, tx->rname );
  164.         }
  165.      }
  166.  
  167.   whwnd = WinCreateStdWindow( HWND_DESKTOP, WS_VISIBLE,
  168.                               &ArtFlags, PMNEWS_CLASS,
  169.                               title_bar, 0L,
  170.                               (HMODULE)0L, ID_MENUBAR, pClient );
  171.  
  172.   if ( whwnd == (HWND)0L )
  173.      {
  174.      logWinErr();
  175.      AbortSN(hwndFrame, *pClient, 9 ); /* Terminate the application */
  176.      }
  177.  
  178.  
  179.   if( !WinSetWindowPos( whwnd, HWND_TOP,
  180.            artloc.artx, artloc.arty, artloc.artwidth, artloc.artheight,
  181.            SWP_ZORDER | SWP_SIZE | SWP_MOVE ) )
  182.          logWinErr();
  183.  
  184.   WinPostMsg( whwnd, WM_USER, (MPARAM) ART_FOCUS, (MPARAM)0 );
  185.   return whwnd;
  186.  
  187. }
  188.  
  189.  
  190. /* the header list dialog window */
  191. static  HWND hdrwin;
  192. /* the current list of articles */
  193. static  ARTICLE *artlist;
  194.  
  195.  
  196.  
  197. static  USHORT  itmx;                 /* selected item index */
  198. static  int     unread;               /* unread in selected thread */
  199. static  ART_ID *curr_article = NULL;  /* current processed article */
  200.  
  201.  
  202. /* copy current article to an output file
  203.    the file is already open; will be closed here */
  204. void copy_article_out( FILE * tmp, TEXT * txt )
  205. {
  206.     aLINE   *ln;
  207.  
  208.  
  209.  
  210.     ln = txt->top;
  211.     while (ln != NULL) {
  212.           fputs(ln->data, tmp);
  213.                 ln = ln->next;
  214.           }
  215.     fputs("\n\n", tmp);
  216.  
  217.     fclose(tmp);
  218. }
  219.  
  220. /******************************************************************************/
  221. /*                                                                            */
  222. /*  close_art_win  deletes current article window and structure               */
  223. /*                                                                            */
  224. /******************************************************************************/
  225. VOID close_art_win( HWND hwndHL )
  226. {
  227. int    idx;
  228. CROSS_POSTS *h, *h0;
  229. ACTIVE *gx;
  230. char   author[128], msg_id[128], wstr[128];
  231.  
  232.  
  233.   /* if utility thread is processing, stop here */
  234.   if ( ( util_func != TASK_FREE ) && ( util_func != SEARCH ) )
  235.      message( "Utility thread in process", "Sorry", MB_OK );
  236.  
  237.  
  238.   /* delete current article window */
  239.   WinDestroyWindow( hwndArt );
  240.   hwndArt = (HWND)0L;
  241.  
  242.  
  243.   /* update the header count of unread in thread */
  244.   if ( unread > 0 ) --unread;
  245.   if ( unread )
  246.      {
  247.      sprintf( wstr, "%03d %03d     %s",
  248.               unread,
  249.               artp->num_articles, artp->header );
  250.      }
  251.   else
  252.      sprintf( wstr, "--- %03d     %s",
  253.               artp->num_articles, artp->header );
  254.  
  255.   WinSendDlgItemMsg( hwndHL, IDD_HRLIST, LM_SETITEMTEXT,
  256.                            MPFROMSHORT( itmx ),
  257.                            MPFROMP( wstr ) );
  258.  
  259.   /* mark this article as read */
  260.   idx = (int) ((curr_article->id) - gp->lo_num - 1);
  261.   *((gp->read_list)+idx) = TRUE;
  262.  
  263.   /* mark the crossposts */
  264.   get_his_stuff(tx, author, msg_id);
  265.  
  266.   if ((h0 = look_up_history(msg_id, gp->group)) != NULL) {
  267.  
  268.        h = h0;
  269.        while (h != NULL) {
  270.              gx = find_news_group(h->group);
  271.              if ( (gx) && (gx->read_list) ) {
  272.                 idx = (int) ((h->art_num) - gx->lo_num - 1);
  273.                 *((gx->read_list)+idx) = TRUE;
  274.              }
  275.             h = h->next;
  276.             }
  277.  
  278.         free_cross_post_list(h0);
  279.         }
  280.  
  281.  
  282.  
  283.   free_article(tx);
  284.   tx = NULL;
  285. }
  286.  
  287. ARTICLE * select_next_unread( ARTICLE * cart, USHORT numi, HWND hwnd )
  288. {
  289.   USHORT nnx;
  290.   ARTICLE *tmpart;
  291.  
  292.   if ( cart == NULL ) return NULL;
  293.   nnx = numi;  tmpart = cart->next;
  294.   while ( tmpart != NULL )
  295.      {
  296.      nnx++;
  297.      if ( count_unread_in_thread( gp, tmpart ) > 0 )
  298.         {
  299.         WinSendDlgItemMsg( hwnd, IDD_HRLIST, LM_SELECTITEM,
  300.                         MPFROMSHORT( nnx ),
  301.                         MPFROMSHORT( TRUE ) );
  302.         return tmpart;
  303.         }
  304.      tmpart  = tmpart->next;
  305.      }
  306.   return NULL;
  307. }
  308.  
  309. /******************************************************************************/
  310. /*                                                                            */
  311. /*  HListProc  receives msgs from IDD_HLIST  (header window )                 */
  312. /*                                                                            */
  313. /******************************************************************************/
  314. MRESULT EXPENTRY HListProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  315. {
  316. static char    *fn;                     /* name of that file */
  317. static int     a_ct;                    /* article count in thread */
  318. static int     firstu;                  /* first unread thread in group */
  319.  
  320. int    idx;
  321. SHORT  uact;
  322. BOOL   get_first_unread;
  323. char   wstr[128];
  324.  
  325.  
  326. /*---------------------------              ----------------------------*/
  327.  
  328.   switch( msg )
  329.     {
  330.  
  331.  
  332.     case WM_INITDLG: {
  333.          ARTICLE *thrd;
  334.          int  urct, hct;
  335.  
  336.          hdrwin = hwnd;  /* save this window's handle outside */
  337.  
  338.          /* get the headers in this group, unless already built */
  339.          if ( artlist == NULL )
  340.             {
  341.             gp = (ACTIVE *)mp2;
  342.             artlist = get_headers( gp );
  343.             }
  344.  
  345.          /* set group name */
  346.          WinSetDlgItemText( hwnd, IDD_GNAME, gp->group );
  347.  
  348.          /* insert them in list box */
  349.          thrd = artlist;
  350.          firstu = -1;  hct = 0;
  351.          while ( thrd != NULL )
  352.            {
  353.            if ( mp2 == (MPARAM)0L )
  354.               urct = 0;
  355.            else
  356.               urct = count_unread_in_thread( gp, thrd );
  357.            if ( urct )
  358.               {
  359.               sprintf( wstr, "%03d %03d     %s", urct,
  360.                        thrd->num_articles, thrd->header );
  361.               if ( firstu == -1 ) firstu = hct;
  362.               }
  363.            else
  364.               sprintf( wstr, "--- %03d     %s",
  365.                        thrd->num_articles, thrd->header );
  366.            WinSendDlgItemMsg( hwnd, IDD_HRLIST, LM_INSERTITEM,
  367.                            MPFROM2SHORT( LIT_END, 0 ),
  368.                            MPFROMP( wstr ) );
  369.  
  370.            hct++;
  371.            thrd = thrd->next;
  372.            }
  373.  
  374.  
  375.          /* now put the highlite on the first unread thread */
  376.          if ( firstu != -1 )
  377.             {
  378.             WinSendDlgItemMsg( hwnd, IDD_HRLIST, LM_SELECTITEM,
  379.                            MPFROMSHORT( firstu ),
  380.                            MPFROMSHORT( TRUE ) );
  381.             }
  382.  
  383.          WinSetFocus( HWND_DESKTOP, hwnd );
  384.          return (MRESULT)TRUE;
  385.          }
  386.  
  387.     case WM_USER:  {
  388.  
  389.         /* if this is to obtain the focus, do so
  390.            and break */
  391.         if ( (ULONG)mp1 == GET_FOCUS )
  392.            {
  393.            WinSetFocus( HWND_DESKTOP, hwnd );
  394.            break;
  395.            }
  396.  
  397.         /* remove current article stuff */
  398.  
  399.         close_art_win( hwnd );
  400.  
  401.         if ((ULONG)mp1 == NEXT_UNREAD || (ULONG)mp1 == NEXT_ARTICLE ||
  402.             (ULONG)mp1 == PREV_ARTICLE )
  403.             {
  404.             if ( (ULONG)mp1 == NEXT_UNREAD )
  405.                 while (curr_article != NULL) {
  406.                       idx = (int)(curr_article->id - gp->lo_num - 1);
  407.                       if ( *((gp->read_list)+idx) == FALSE) break;
  408.                       a_ct++;
  409.                       curr_article = curr_article->next_art;
  410.                       }
  411.             else
  412.             if ( ( (ULONG)mp1 == PREV_ARTICLE ) &&
  413.                  ( curr_article->last_art != NULL ) )
  414.                {
  415.                a_ct--;
  416.                curr_article = curr_article->last_art;
  417.                }
  418.             else
  419.                {
  420.                a_ct++;
  421.                curr_article = curr_article->next_art;
  422.                }
  423.  
  424.             if (curr_article == NULL)
  425.                {
  426.                if ( (ULONG)mp1 == NEXT_UNREAD )
  427.                   {
  428.                   artp = select_next_unread( artp, itmx, hwnd );
  429.                   if ( artp == NULL )
  430.                      {
  431.                      WinSendMsg( hwnd, WM_CLOSE, 0L, 0L );
  432.                      WinDestroyWindow( hwnd );
  433.                      }
  434.                   else
  435.                      WinPostMsg( hwnd, WM_USER, (MPARAM) GET_FOCUS, (MPARAM)0 );
  436.                   }
  437.                break;
  438.                }
  439.             else
  440.                {
  441.                a_ct++;
  442.                tx = load_article(fn, curr_article->art_off);
  443.  
  444.  
  445.                hwndArt = open_art_win( &hwndClient, artp->header );
  446.  
  447.                break;
  448.                }
  449.             }
  450.  
  451.  
  452.  
  453.          if ((ULONG)mp1 == STOP_READING)
  454.             return 0;
  455.  
  456.          break;
  457.          }  /* end WM_USER */
  458.  
  459.  
  460.     case WM_COMMAND: {
  461.          USHORT command;                   /* WM_COMMAND command value     */
  462.  
  463.         command = SHORT1FROMMP(mp1);      /* Extract the command value    */
  464.  
  465.         switch (command)
  466.           {
  467.           case IDD_HMARK:   {
  468.              /* mark all articles in current thread as read */
  469.              if ( artp != NULL )
  470.                 {
  471.                 mark_read_in_thread( gp, artp );
  472.                 unread = 0;
  473.                 sprintf( wstr, "--- %03d     %s",
  474.                  artp->num_articles, artp->header );
  475.  
  476.                 WinSendDlgItemMsg( hwnd, IDD_HRLIST, LM_SETITEMTEXT,
  477.                            MPFROMSHORT( itmx ),
  478.                            MPFROMP( wstr ) );
  479.                 /* set focus back to this window from 'mark' */
  480.                 WinPostMsg( hwnd, WM_USER, (MPARAM) GET_FOCUS, (MPARAM)0 );
  481.                 }
  482.              return 0;
  483.              }
  484.           default: return 0;
  485.           }
  486.         break;
  487.         }
  488.  
  489.     /* indicates user wants the 1st article, read or unread */
  490.     case WM_BUTTON2DOWN:
  491.          uact = LN_ENTER;
  492.          get_first_unread = FALSE;
  493.          goto Rbutton;
  494.  
  495.  
  496.  
  497.  
  498.     /* process ESC and TAB as in SNEWS */
  499.     case WM_CHAR: {
  500.       USHORT keyflag;
  501.       USHORT vkey, ch;
  502.       UCHAR  scan;
  503.  
  504.       keyflag = SHORT1FROMMP( mp1 );
  505.       vkey    = SHORT2FROMMP( mp2 );
  506.       ch      = SHORT1FROMMP( mp2 );
  507.       scan    = CHAR1FROMMP( mp1 );
  508.  
  509.  
  510.  
  511.       if ( !( keyflag & KC_KEYUP ) )
  512.          {
  513.          switch ( vkey )
  514.            {
  515.  
  516.            /* keys for SNEWS emulation */
  517.            case VK_ESC:
  518.               WinSendMsg( hwnd, WM_CLOSE, 0L, 0L );
  519.               WinDestroyWindow( hwnd );
  520.               break;
  521.            case VK_TAB:
  522.               /* select next unread thread */
  523.  
  524.               artp = select_next_unread( artp, itmx, hwnd );
  525.               if ( artp == NULL )
  526.                  {
  527.                  WinSendMsg( hwnd, WM_CLOSE, 0L, 0L );
  528.                  WinDestroyWindow( hwnd );
  529.                  }
  530.               else
  531.                  WinPostMsg( hwnd, WM_USER, (MPARAM) GET_FOCUS, (MPARAM)0 );
  532.               break;
  533.            default: {
  534.               if ( ( scan == 5 ) && ( ch == 0x2b ) ) /* far plus key */
  535.                  {
  536.                  artp = select_next_unread( artp, itmx, hwnd );
  537.                  if ( artp == NULL )
  538.                     {
  539.                     WinSendMsg( hwnd, WM_CLOSE, 0L, 0L );
  540.                     WinDestroyWindow( hwnd );
  541.                     }
  542.                  else
  543.                     WinPostMsg( hwnd, WM_USER, (MPARAM) GET_FOCUS, (MPARAM)0 );
  544.                  }
  545.               break;
  546.               }
  547.            }
  548.          }
  549.  
  550.  
  551.       break;
  552.       }
  553.  
  554.     case WM_CONTROL: {
  555.       USHORT  cname, nix;
  556.  
  557.       cname = SHORT1FROMMP( mp1 );
  558.       get_first_unread = TRUE;
  559.       if  ( cname == IDD_HRLIST )
  560.           {
  561.           uact = SHORT2FROMMP( mp1 );
  562.           if ( ( uact == LN_ENTER ) ||
  563.                ( uact == LN_SELECT ) )
  564.              {
  565.           Rbutton:
  566.              /* if an article window is active, close it */
  567.              if ( hwndArt != (HWND)0L )
  568.                 {
  569.                 close_art_win( hwnd );
  570.                 }
  571.  
  572.              /* a thread has been selected */
  573.              itmx = (USHORT) WinSendDlgItemMsg( hwnd, IDD_HRLIST,
  574.                            LM_QUERYSELECTION,
  575.                            NULL, NULL );
  576.  
  577.              nix = 0;  artp = artlist;
  578.              while ( ( artp != NULL ) && ( nix != itmx ) )
  579.                  {
  580.                  nix++;
  581.                  artp  = artp->next;
  582.                  }
  583.  
  584.              if ( ( artp != NULL ) && ( uact == LN_ENTER ) )
  585.                 {  /* read 1st  article in the thread */
  586.  
  587.                 fn = make_news_group_name(gp->group);
  588.  
  589.                 unread = count_unread_in_thread( gp, artp );
  590.  
  591.                 curr_article = artp->art_num;
  592.                 a_ct = 1;
  593.                 if ( get_first_unread )
  594.                 while (curr_article != NULL) {
  595.                       idx = (int)(curr_article->id - gp->lo_num - 1);
  596.                       if ( *((gp->read_list)+idx) == FALSE) break;
  597.                       a_ct++;
  598.                       curr_article = curr_article->next_art;
  599.                       }
  600.  
  601.                 if ( curr_article == NULL )
  602.                    curr_article = artp->art_num;
  603.                 tx = load_article(fn, curr_article->art_off);
  604.  
  605.                 hwndArt = open_art_win( &hwndClient, artp->header );
  606.                 }
  607.              }
  608.  
  609.           }   /* end IDD_HRLIST */
  610.  
  611.       break;
  612.       }
  613.  
  614.  
  615.     case WM_CLOSE:   {
  616.              if ( hwndArt != (HWND)0L )
  617.                 close_art_win( hwnd );
  618.          }
  619.     }
  620.  
  621.   return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  622.  
  623. }  /* end HlistProc */
  624.  
  625. static HWND hwndSrch;
  626. static char Srchstr[41];
  627. /******************************************************************************/
  628. /*                                                                            */
  629. /*  SrchProc obtains the string for a newsgroup search                        */
  630. /*                                                                            */
  631. /******************************************************************************/
  632. MRESULT EXPENTRY SrchProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  633. {
  634.   static  HWND  psrchstr;
  635.  
  636.   switch( msg )
  637.   {
  638.   case WM_INITDLG:  {
  639.  
  640.      psrchstr = WinWindowFromID( hwnd, IDE_SRCHSTR );
  641.      WinSendMsg( psrchstr, EM_SETTEXTLIMIT,
  642.                  MPFROMLONG( 40 ), MPFROMLONG( 0 ) );
  643.  
  644.      WinSetWindowText( psrchstr, Srchstr );
  645.  
  646.      WinSetFocus( HWND_DESKTOP, psrchstr );
  647.      return (MRESULT)TRUE;
  648.      }
  649.  
  650.     case WM_CHAR: {
  651.       USHORT keyflag;
  652.       USHORT vkey;
  653.  
  654.       keyflag = SHORT1FROMMP( mp1 );
  655.       vkey    = SHORT2FROMMP( mp2 );
  656.  
  657.       if ( !( keyflag & KC_KEYUP ) )
  658.          {
  659.          switch ( vkey )
  660.            {
  661.            case VK_NEWLINE:
  662.                 WinQueryWindowText( psrchstr,
  663.                              sizeof(Srchstr), Srchstr );
  664.                 WinSendMsg( hwndFrame, WM_USER,
  665.                      MPFROMLONG(START_SEARCH), MPFROMLONG(0L) );
  666.                 WinDestroyWindow( hwndSrch );
  667.            }
  668.          }
  669.       break;
  670.       }
  671.  
  672.     case WM_COMMAND: {
  673.       USHORT cmd;
  674.  
  675.       cmd = SHORT1FROMMP( mp1 );
  676.  
  677.       if ( cmd == IDE_SBOK )
  678.          {
  679.          WinQueryWindowText( psrchstr,
  680.                              sizeof(Srchstr), Srchstr );
  681.          WinSendMsg( hwndFrame, WM_USER,
  682.                      MPFROMLONG(START_SEARCH), MPFROMLONG(0L) );
  683.          WinDestroyWindow( hwndSrch );
  684.          }
  685.       else
  686.       if ( cmd == IDE_SBCAN )
  687.          {
  688.          /* indicate to requestor that we cancelled */
  689.          WinSendMsg( hwndFrame, WM_USER,
  690.                      MPFROMLONG(WE_CANCELLED), MPFROMLONG(0L) );
  691.          WinDestroyWindow( hwndSrch );
  692.          }
  693.  
  694.       break;
  695.       }
  696.  
  697.   }
  698.  
  699.   return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  700. }
  701.  
  702.  
  703. /******************************************************************************/
  704. /*                                                                            */
  705. /*  GListProc  receives msgs from IDD_GLIST  (Group window )                  */
  706. /*                                                                            */
  707. /******************************************************************************/
  708. MRESULT EXPENTRY GListProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  709. {
  710.   static  ACTIVE  *head;
  711.   static  ACTIVE  *anchor;
  712.   static  USHORT   iix = 0;
  713.  
  714.   USHORT           nix;
  715.   int              ur, totla;
  716.   char             *rcfld, *rcmsg;  /* data returned from load_stuff */
  717.   char             stats[80];
  718.  
  719.   switch( msg )
  720.     {
  721.  
  722.  
  723.     case WM_INITDLG: {
  724.       /*  load up the SNEWS .rc stuff.  Do this single-threaded now;
  725.           later, it can be started in another thread and send us a msg
  726.           when it's done */
  727.     ACTIVE  *gptr, *fgptr;
  728.     int      firstg;     /* first group with unread */
  729.  
  730.     hwndLbox = hwnd;
  731.     if (load_stuff( &rcfld, &rcmsg )) {
  732.         head = load_active_file();
  733.         load_read_list();
  734.         nicks = load_alias_file();
  735.         load_history_list();
  736.         }
  737.       else
  738.         {
  739.         sprintf( stats, rcmsg, rcfld );
  740.         message( stats, "PMNews RC file Error", MB_CANCEL );
  741.         /* Terminate the application    */
  742.         AbortSN(hwndFrame, hwndClient, MSGBOXID+1 );
  743.         }
  744.  
  745.       /* fill the list box with news groups */
  746.       WinSendDlgItemMsg( hwnd, IDD_GRLIST, LM_DELETEALL, NULL, NULL );
  747.       gptr = head;
  748.       iix = 0;
  749.       firstg = -1;
  750.       while  ( gptr != NULL )
  751.         {
  752.         ur = count_unread_in_group(gptr);
  753.         totla = gptr->hi_num - gptr->lo_num;
  754.         if ( ur )
  755.            {
  756.            if ( firstg == -1 )
  757.               {
  758.               firstg = iix;  fgptr = gptr;
  759.               }
  760.            sprintf( stats, "%04d (%04d)     ", ur, totla );
  761.            }
  762.         else
  763.            sprintf( stats, "---- (%04d)     ", totla );
  764.         strcat( stats, gptr->group );
  765.         WinSendDlgItemMsg( hwnd, IDD_GRLIST, LM_INSERTITEM,
  766.                            MPFROM2SHORT( LIT_END, 0 ),
  767.                            MPFROMP( stats ) );
  768.  
  769.  
  770.         iix++;
  771.         gptr = gptr->next;
  772.         }
  773.  
  774.       anchor = NULL;
  775.       /* now put the highlite on the first unread group */
  776.       if ( firstg != -1 )
  777.          {
  778.          anchor = fgptr;
  779.          WinSendDlgItemMsg( hwnd, IDD_GRLIST, LM_SELECTITEM,
  780.                            MPFROMSHORT( firstg ),
  781.                            MPFROMSHORT( TRUE ) );
  782.          }
  783.  
  784.       WinSetFocus( HWND_DESKTOP, hwnd );
  785.       return (MRESULT)TRUE;
  786.       }
  787.  
  788.  
  789.     case WM_COMMAND: {
  790.       USHORT  cmd;
  791.       cmd = SHORT1FROMMP( mp1 );
  792.  
  793.       switch ( cmd )
  794.         {
  795.         case IDD_GMARK: {
  796.           /* look up the corresponding group and mark
  797.              everything read */
  798.           nix = 0; anchor = head;
  799.           while ( ( anchor != NULL ) && ( nix != iix ) )
  800.                 {
  801.                 nix++;
  802.                 anchor  = anchor->next;
  803.                 }
  804.           if ( nix == iix )
  805.              {
  806.              totla = anchor->hi_num - anchor->lo_num;
  807.              mark_group_as_read( anchor );
  808.              sprintf( stats, "---- (%04d)     ", totla );
  809.              strcat( stats, anchor->group );
  810.              WinSendDlgItemMsg( hwnd, IDD_GRLIST, LM_SETITEMTEXT,
  811.                            MPFROMSHORT( iix ),
  812.                            MPFROMP( stats ) );
  813.              }
  814.           break;
  815.           }  /* end gmark */
  816.  
  817.         case IDD_SEARCH: {
  818.           /* pop open search entry dialog */
  819.           hwndSrch = WinLoadDlg( HWND_DESKTOP, HWND_DESKTOP,
  820.                         (PFNWP) SrchProc,
  821.                         (HMODULE)0L, IDD_SRCHBOX,
  822.                          NULL );
  823.           break;
  824.           }  /* end search */
  825.  
  826.         }
  827.       break;
  828.       }
  829.  
  830.  
  831.  
  832.     case WM_USER:    {
  833.  
  834.       switch ( (ULONG)mp1) {
  835.  
  836.          case NEXT_UNREAD:
  837.             {
  838.             /* scan from current index */
  839.             return 0;
  840.             }
  841.          case WE_CANCELLED:
  842.             {
  843.             return 0;
  844.             }
  845.          case START_SEARCH:
  846.             {
  847.             gp = anchor;
  848.             DO_UTIL( SEARCH );
  849.             return 0;
  850.             }
  851.          case DISP_LIST:
  852.             {
  853.             WinDlgBox( HWND_DESKTOP, hwnd,
  854.                        (PFNWP) HListProc,
  855.                        (HMODULE)0L, IDD_HLIST,
  856.                        MPFROMLONG( 0L ) );  /* 0 indicates artlist loaded */
  857.             free_header( artlist );
  858.             WinSetFocus( HWND_DESKTOP, hwnd );
  859.             return 0;
  860.             }
  861.  
  862.          case MAIL_FILERR: {
  863.             message( (PSZ) PVOIDFROMMP(mp2), "Sorry", MB_OK );
  864.             return 0;
  865.             }
  866.          }
  867.       break;
  868.       }
  869.  
  870.  
  871.     case WM_CONTROL: {
  872.       USHORT  cname;
  873.  
  874.       cname = SHORT1FROMMP( mp1 );
  875.  
  876.       if  ( cname == IDD_GRLIST )
  877.           {
  878.           if ( ( SHORT2FROMMP( mp1 ) == LN_SELECT ) ||
  879.                ( SHORT2FROMMP( mp1 ) == LN_ENTER ) )
  880.  
  881.              {
  882.              iix = (USHORT) WinSendDlgItemMsg( hwnd, IDD_GRLIST, LM_QUERYSELECTION,
  883.                            NULL, NULL );
  884.  
  885.              nix = 0; anchor = head;
  886.              while ( ( anchor != NULL ) && ( nix != iix ) )
  887.                  {
  888.                  nix++;
  889.                  anchor  = anchor->next;
  890.                  }
  891.              if ( ( SHORT2FROMMP( mp1 ) == LN_ENTER ) &&
  892.                 ( nix == iix ) )
  893.                 {  /* open a list box for this group */
  894.                    artlist = NULL;
  895.                    if ( WinDlgBox( HWND_DESKTOP, hwnd,
  896.                             (PFNWP) HListProc,
  897.                             (HMODULE)0L, IDD_HLIST,
  898.                             MPFROMP( anchor ) ) != 0L )
  899.                             {
  900.                             if ( artlist != NULL )
  901.                                {
  902.                                free_header( artlist );
  903.                                }
  904.                             WinInvalidateRect( hwnd, NULL, FALSE );
  905.                             WinSetFocus( HWND_DESKTOP, hwnd );
  906.                             }
  907.                    else logWinErr();
  908.  
  909.                    ur = count_unread_in_group(anchor);
  910.                    totla = anchor->hi_num - anchor->lo_num;
  911.                    if ( ur )
  912.                       sprintf( stats, "%04d (%04d)     ", ur, totla );
  913.                    else
  914.                       sprintf( stats, "---- (%04d)     ", totla );
  915.  
  916.                    strcat( stats, anchor->group );
  917.                    WinSendDlgItemMsg( hwnd, IDD_GRLIST, LM_SETITEMTEXT,
  918.                            MPFROMSHORT( iix ),
  919.                            MPFROMP( stats ) );
  920.  
  921.                 }
  922.              }
  923.  
  924.           }
  925.  
  926.       break;
  927.       }
  928.  
  929.     case WM_DESTROY: {
  930.       free_hist_list();
  931.       save_read_list();
  932.       close_active_file();
  933.       }
  934.  
  935.     }
  936.  
  937.   return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  938. }
  939.  
  940.  
  941. /******************************************************************************/
  942. /*                                                                            */
  943. /*  FileProc handles selection for saving an article to disk                  */
  944. /*  the path name will be saved in the global savepath                                                                          */
  945. /*  it returns a yea or nay for continuing to save.                          */
  946. /*                                                                            */
  947. /******************************************************************************/
  948. BOOL   FileProc( HWND hwnd )
  949. {
  950.   FILEDLG  gsave;
  951.   HWND     ret;
  952.  
  953.   memset( &gsave, 0, sizeof(FILEDLG) );
  954.   gsave.cbSize = sizeof(FILEDLG);
  955.   gsave.fl = FDS_SAVEAS_DIALOG | FDS_CENTER;
  956.   strcpy( gsave.szFullFile, "*.SPB" );
  957.   gsave.pszTitle = "Save Article in File";
  958.   gsave.pszOKButton = "Save Article";
  959.  
  960.   ret = WinFileDlg( hwnd, hwnd, &gsave );
  961.   if ( ret == 0 )
  962.      {
  963.      message( "Unable to open File Dialog", "Sorry", MB_CANCEL );
  964.      return FALSE;
  965.      }
  966.  
  967.   if ( gsave.lReturn == DID_OK )
  968.      {
  969.      strcpy( savepath, gsave.szFullFile );
  970.      return TRUE;
  971.      }
  972.   else
  973.      {
  974.      savepath[0] = '\0';
  975.      return FALSE;
  976.      }
  977. }
  978.  
  979. /******************************************************************************/
  980. /*                                                                            */
  981. /*  MboxProc handles queries for mail addressee                               */
  982. /*                                                                            */
  983. /******************************************************************************/
  984. MRESULT EXPENTRY MboxProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  985. {
  986.   static  HWND  mailad;
  987.  
  988.   switch( msg )
  989.   {
  990.   case WM_INITDLG:  {
  991.      ALII  *ap;
  992.      char   aliastr[196];
  993.      SHORT  itx;
  994.      MRESULT mrs;
  995.  
  996.      recipient[0] = '\0';  /* set null to start */
  997.  
  998.      mailad = WinWindowFromID( hwnd, IDE_MAILADR );
  999.      WinSendMsg( mailad, EM_SETTEXTLIMIT,
  1000.                  MPFROMLONG( 80 ), MPFROMLONG( 0 ) );
  1001.  
  1002.      /* fill the list box with alias entries */
  1003.      WinSendDlgItemMsg( hwnd, IDD_MAILIST, LM_DELETEALL, NULL, NULL );
  1004.      ap = nicks;
  1005.      while  ( ap != NULL )
  1006.         {
  1007.         sprintf( aliastr, " %-*s   %s ", szalias+3, ap->nick, ap->name );
  1008.         mrs = WinSendDlgItemMsg( hwnd, IDD_MAILIST, LM_INSERTITEM,
  1009.                            MPFROM2SHORT( LIT_SORTASCENDING, 0 ),
  1010.                            MPFROMP( &aliastr[0] ) );
  1011.  
  1012.         itx = SHORT1FROMMR( mrs );
  1013.         WinSendDlgItemMsg( hwnd, IDD_MAILIST, LM_SETITEMHANDLE,
  1014.                            MPFROMSHORT( itx ),
  1015.                            MPFROMP( ap ) );
  1016.         ap = ap->nextp;
  1017.         }
  1018.  
  1019.      WinSetFocus( HWND_DESKTOP, mailad );
  1020.      return (MRESULT)TRUE;
  1021.      }
  1022.  
  1023.  
  1024.   case WM_COMMAND: {
  1025.      USHORT cmd;
  1026.  
  1027.      cmd = SHORT1FROMMP( mp1 );
  1028.  
  1029.      if ( cmd == IDE_GSOK2 )
  1030.         {
  1031.          WinQueryWindowText( mailad,
  1032.                              sizeof(recipient), recipient );
  1033.          WinSendMsg( hwndClient, WM_USER,
  1034.                      MPFROMLONG(MAIL_ARTICLE), MPFROMLONG(0L) );
  1035.          WinDestroyWindow( hwnd );
  1036.         }
  1037.  
  1038.       if ( cmd == IDE_GSCAN2 )
  1039.          {
  1040.          /* indicate to requestor that we cancelled */
  1041.          WinSendMsg( hwndClient, WM_USER,
  1042.                      MPFROMLONG(WE_CANCELLED), MPFROMLONG(0L) );
  1043.          WinDestroyWindow( hwnd );
  1044.          }
  1045.  
  1046.       break;
  1047.       }
  1048.  
  1049.     case WM_CONTROL: {
  1050.       USHORT  cname, iix;
  1051.       ALII   *tp;
  1052.  
  1053.       cname = SHORT1FROMMP( mp1 );
  1054.  
  1055.       if  ( cname == IDD_MAILIST )
  1056.           {
  1057.           if ( ( SHORT2FROMMP( mp1 ) == LN_ENTER ) ||
  1058.                ( SHORT2FROMMP( mp1 ) == LN_SELECT ) )
  1059.              {
  1060.              iix = SHORT1FROMMR( WinSendDlgItemMsg( hwnd, IDD_MAILIST, LM_QUERYSELECTION,
  1061.                            NULL, NULL ) );
  1062.              tp = (ALII *) WinSendDlgItemMsg( hwnd, IDD_MAILIST, LM_QUERYITEMHANDLE,
  1063.                            MPFROMSHORT( iix ), NULL );
  1064.  
  1065.  
  1066.              strcpy( recipient, tp->nick );
  1067.  
  1068.              if  ( SHORT2FROMMP( mp1 ) == LN_ENTER )
  1069.                  {
  1070.                  WinSendMsg( hwndClient, WM_USER,
  1071.                      MPFROMLONG(MAIL_ARTICLE), MPFROMLONG(0L) );
  1072.                  WinDestroyWindow( hwnd );
  1073.                  }
  1074.              break;
  1075.              }
  1076.           }
  1077.       break;
  1078.       }
  1079.  
  1080.   }
  1081.   return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  1082. }
  1083.  
  1084. static HWND   hwndSubj;
  1085.  
  1086. /******************************************************************************/
  1087. /*                                                                            */
  1088. /*  SboxProc handles queries for posting subject & group                      */
  1089. /*                                                                            */
  1090. /******************************************************************************/
  1091. MRESULT EXPENTRY SboxProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  1092. {
  1093.   static  HWND  pgroup, psubject;
  1094.  
  1095.   switch( msg )
  1096.   {
  1097.   case WM_INITDLG:  {
  1098.      pgroup = WinWindowFromID( hwnd, IDE_GROUP );
  1099.      psubject = WinWindowFromID( hwnd, IDE_SUBJ );
  1100.      WinSendMsg( pgroup, EM_SETTEXTLIMIT,
  1101.                  MPFROMLONG( 80 ), MPFROMLONG( 0 ) );
  1102.      WinSendMsg( psubject, EM_SETTEXTLIMIT,
  1103.                  MPFROMLONG( 80 ), MPFROMLONG( 0 ) );
  1104.  
  1105.      if ( gp != NULL )
  1106.         {
  1107.         strcpy( ngroup, gp->group );
  1108.         WinSetWindowText( pgroup, gp->group );
  1109.         }
  1110.  
  1111.      if ( artp != NULL )
  1112.         {
  1113.         strcpy( nsubj, artp->header );
  1114.         eat_gunk( nsubj );
  1115.         WinSetWindowText( psubject, nsubj );
  1116.         }
  1117.  
  1118.      WinSetFocus( HWND_DESKTOP, psubject );
  1119.      return (MRESULT)TRUE;
  1120.      }
  1121.  
  1122.  
  1123.     case WM_COMMAND: {
  1124.       USHORT cmd;
  1125.  
  1126.       cmd = SHORT1FROMMP( mp1 );
  1127.  
  1128.       if ( cmd == IDE_GSOK )
  1129.          {
  1130.          WinQueryWindowText( pgroup,
  1131.                              sizeof(ngroup), ngroup );
  1132.  
  1133.  
  1134.          WinQueryWindowText( psubject,
  1135.                              sizeof(nsubj), nsubj );
  1136.          WinSendMsg( hwndArt, WM_USER,
  1137.                      MPFROMLONG(POST_ARTICLE), MPFROMLONG(0L) );
  1138.          WinDestroyWindow( hwndSubj );
  1139.          }
  1140.  
  1141.       if ( cmd == IDE_GSCAN )
  1142.          {
  1143.          /* indicate to requestor that we cancelled */
  1144.          WinSendMsg( hwndArt, WM_USER,
  1145.                      MPFROMLONG(WE_CANCELLED), MPFROMLONG(0L) );
  1146.          WinDestroyWindow( hwndSubj );
  1147.          }
  1148.  
  1149.       break;
  1150.       }
  1151.  
  1152.   }
  1153.   return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  1154. }
  1155.  
  1156.  
  1157. /******************************************************************************/
  1158. /*                                                                            */
  1159. /*  ArticleProc handles the detail display of text                            */
  1160. /*                                                                            */
  1161. /******************************************************************************/
  1162. MRESULT EXPENTRY ArticleProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  1163. {
  1164. static aLINE *topline;    /* top line in window */
  1165. static FONTMETRICS fm;
  1166. static HPS    hps;
  1167. static HWND   hwndScroll;
  1168. static int lcnt;  /* lines displayed */
  1169. static USHORT linehite;
  1170. static ULONG  currfunc = 0L;
  1171.  
  1172.  
  1173.  
  1174.  
  1175. /* article window size */
  1176. static SHORT  cyClient;
  1177.  
  1178.   switch( msg )
  1179.   {
  1180.  
  1181.     case WM_CREATE:
  1182.       {
  1183.       USHORT pos, itemx;
  1184.       HWND   hwndmenu;
  1185.       USHORT nxAttrib, nuAttrib, npAttrib;
  1186.       ART_ID *wart;
  1187.  
  1188.       /* set up to show curr_article */
  1189.  
  1190.       topline = tx->start;  /* 1st show line past header */
  1191.  
  1192.  
  1193.       hwndScroll = WinWindowFromID( WinQueryWindow( hwnd, QW_PARENT ),
  1194.                    FID_VERTSCROLL );
  1195.       /* set the scroll bar past header */
  1196.       pos = topline->index - 1;
  1197.       WinSendMsg( hwndScroll, SBM_SETSCROLLBAR, MPFROM2SHORT( pos, 0 ),
  1198.                   MPFROM2SHORT( 0, tx->lines - 1 ) );
  1199.  
  1200.       /* find the menu bar handle */
  1201.       hwndmenu = WinWindowFromID( WinQueryWindow( hwnd, QW_PARENT ),
  1202.                    FID_MENU );
  1203.  
  1204.       nxAttrib = SHORT1FROMMP( WinSendMsg( hwndmenu, MM_QUERYITEMATTR,
  1205.                                MPFROM2SHORT( IDM_NEXTART, TRUE ),
  1206.                                (MPARAM)MIA_DISABLED ) );
  1207.       nuAttrib = SHORT1FROMMP( WinSendMsg( hwndmenu, MM_QUERYITEMATTR,
  1208.                                MPFROM2SHORT( IDM_NEXTUNR, TRUE ),
  1209.                                (MPARAM)MIA_DISABLED ) );
  1210.       npAttrib = SHORT1FROMMP( WinSendMsg( hwndmenu, MM_QUERYITEMATTR,
  1211.                                MPFROM2SHORT( IDM_PREVART, TRUE ),
  1212.                                (MPARAM)MIA_DISABLED ) );
  1213.  
  1214.  
  1215.       /* if there is no 'prev' article, disable option */
  1216.       if ( curr_article->last_art == NULL )
  1217.          {
  1218.          npAttrib |= MIA_DISABLED;
  1219.          WinSendMsg( hwndmenu, MM_SETITEMATTR,
  1220.                      MPFROM2SHORT( IDM_PREVART, TRUE ),
  1221.                      MPFROM2SHORT( MIA_DISABLED, npAttrib ) );
  1222.          }
  1223.  
  1224.  
  1225.       /* if there is no 'next' article, disable options */
  1226.       if ( curr_article->next_art == NULL )
  1227.          {
  1228.          nxAttrib |= MIA_DISABLED;
  1229.          nuAttrib |= MIA_DISABLED;
  1230.          WinSendMsg( hwndmenu, MM_SETITEMATTR,
  1231.                      MPFROM2SHORT( IDM_NEXTART, TRUE ),
  1232.                      MPFROM2SHORT( MIA_DISABLED, nxAttrib ) );
  1233.          WinSendMsg( hwndmenu, MM_SETITEMATTR,
  1234.                      MPFROM2SHORT( IDM_NEXTUNR, TRUE ),
  1235.                      MPFROM2SHORT( MIA_DISABLED, nuAttrib ) );
  1236.  
  1237.          }
  1238.       else  /* scan for unread (slow) */
  1239.          {
  1240.          wart = curr_article->next_art;
  1241.          while (wart != NULL)
  1242.                {
  1243.                itemx = (int)(wart->id - gp->lo_num - 1);
  1244.                if ( *((gp->read_list)+itemx) == FALSE) break;
  1245.                wart = wart->next_art;
  1246.                }
  1247.          if ( wart == NULL )
  1248.             {
  1249.             nuAttrib |= MIA_DISABLED;
  1250.             WinSendMsg( hwndmenu, MM_SETITEMATTR,
  1251.                      MPFROM2SHORT( IDM_NEXTUNR, TRUE ),
  1252.                      MPFROM2SHORT( MIA_DISABLED, nuAttrib ) );
  1253.             }
  1254.          }
  1255.  
  1256.  
  1257.       WinSetFocus( HWND_DESKTOP, hwnd );
  1258.       return 0;
  1259.       }
  1260.  
  1261.     case WM_SIZE: {
  1262.       /* save the resize values */
  1263.  
  1264.       /* cxClient = SHORT1FROMMP(mp2); */
  1265.       cyClient = SHORT2FROMMP(mp2);
  1266.  
  1267.  
  1268.       break;  }
  1269.  
  1270.  
  1271.     case WM_COMMAND:
  1272.       {
  1273.       USHORT command;                   /* WM_COMMAND command value     */
  1274.  
  1275.       command = SHORT1FROMMP(mp1);      /* Extract the command value    */
  1276.  
  1277.       switch (command)
  1278.         {
  1279.         case IDM_RETHDRS: {
  1280.              WinSendMsg( hdrwin, WM_USER, (MPARAM) STOP_READING, NULL );
  1281.              return 0;
  1282.              }
  1283.  
  1284.         case IDM_NEXTUNR:  {
  1285.              WinSendMsg( hdrwin, WM_USER, (MPARAM) NEXT_UNREAD, NULL );
  1286.              return 0;
  1287.              }
  1288.  
  1289.         case IDM_NEXTART:  {
  1290.              WinSendMsg( hdrwin, WM_USER, (MPARAM) NEXT_ARTICLE, NULL );
  1291.              return 0;
  1292.              }
  1293.  
  1294.         case IDM_PREVART:  {
  1295.              WinSendMsg( hdrwin, WM_USER, (MPARAM) PREV_ARTICLE, NULL );
  1296.              return 0;
  1297.              }
  1298.  
  1299.         case IDM_MAILART: {
  1300.              currfunc = IDM_MAILART;
  1301.              /* open dialog box for addressee */
  1302.              hwndSubj = WinLoadDlg( HWND_DESKTOP, HWND_DESKTOP,
  1303.                         (PFNWP) MboxProc,
  1304.                         (HMODULE)0L, IDD_MAILBOX,
  1305.                          NULL );
  1306.              return 0;
  1307.              }
  1308.  
  1309.         case IDM_REPLY:  {
  1310.              currfunc = IDM_REPLY;
  1311.              DO_UTIL( REPART );
  1312.              return 0;
  1313.              }
  1314.  
  1315.         case IDM_PRINT:    {
  1316.              DO_UTIL( PRINT );
  1317.              return 0;
  1318.              }
  1319.  
  1320.         case IDM_SAVED:    {
  1321.              if ( FileProc( hwnd ) )
  1322.                 DO_UTIL( SAVED );
  1323.              return 0;
  1324.              }
  1325.  
  1326.         case IDM_NEWPOST:  {
  1327.              currfunc = IDM_NEWPOST;
  1328.              /* open dialog box for subject, group */
  1329.              hwndSubj = WinLoadDlg( HWND_DESKTOP, HWND_DESKTOP,
  1330.                         (PFNWP) SboxProc,
  1331.                         (HMODULE)0L, IDD_SUBBOX,
  1332.                          NULL );
  1333.              return 0;
  1334.              }
  1335.  
  1336.         case IDM_FOLLOWUP:  {
  1337.              currfunc = IDM_FOLLOWUP;
  1338.              strcpy( ngroup, gp->group );
  1339.              strcpy( nsubj, artp->header );
  1340.              eat_gunk( nsubj );
  1341.  
  1342.              /* quote article? */
  1343.              quotans = message( "Quote Article?", "Which?", MB_YESNO );
  1344.  
  1345.              /* schedule  edit session */
  1346.              DO_UTIL( POST_EDIT );
  1347.              return 0;
  1348.              }
  1349.  
  1350.         default:
  1351.           return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  1352.         }
  1353.       break;
  1354.       }
  1355.  
  1356.  
  1357.     /* send corresponding scroll bar messages */
  1358.     case WM_CHAR: {
  1359.       USHORT keyflag;
  1360.       USHORT vkey, ch;
  1361.       UCHAR  scan;
  1362.  
  1363.       keyflag = SHORT1FROMMP( mp1 );
  1364.       vkey    = SHORT2FROMMP( mp2 );
  1365.       scan    = CHAR1FROMMP( mp1 );
  1366.       ch      = SHORT1FROMMP( mp2 );
  1367.  
  1368.       if ( !( keyflag & KC_KEYUP ) )
  1369.          {
  1370.          if ( ( scan == 7 ) && ( ch == 0x0d ) )
  1371.             { /* far Enter key */
  1372.              WinSendMsg( hdrwin, WM_USER, (MPARAM) NEXT_ARTICLE, NULL );
  1373.              return 0;
  1374.             }
  1375.  
  1376.          if ( scan == 5 )
  1377.             {
  1378.             if ( ch == 0x2b )
  1379.                /* far plus key */
  1380.                WinSendMsg( hdrwin, WM_USER, (MPARAM) NEXT_UNREAD, NULL );
  1381.             else
  1382.             if ( ch == 0x2d )
  1383.                /* far minus key */
  1384.                WinSendMsg( hdrwin, WM_USER, (MPARAM) PREV_ARTICLE, NULL );
  1385.              return 0;
  1386.             }
  1387.  
  1388.  
  1389.          switch ( vkey )
  1390.            {
  1391.            case VK_PAGEUP:
  1392.               WinSendMsg( hwnd, WM_VSCROLL, 0L,
  1393.                  MPFROM2SHORT( 0, SB_PAGEUP ) );
  1394.               break;
  1395.            case VK_PAGEDOWN:
  1396.               WinSendMsg( hwnd, WM_VSCROLL, 0L,
  1397.                  MPFROM2SHORT( 0, SB_PAGEDOWN ) );
  1398.               break;
  1399.            case VK_UP:
  1400.               WinSendMsg( hwnd, WM_VSCROLL, 0L,
  1401.                  MPFROM2SHORT( 0, SB_LINEUP ) );
  1402.               break;
  1403.            case VK_DOWN:
  1404.               WinSendMsg( hwnd, WM_VSCROLL, 0L,
  1405.                  MPFROM2SHORT( 0, SB_LINEDOWN ) );
  1406.               break;
  1407.  
  1408.            /* keys for SNEWS emulation */
  1409.            case VK_ESC:
  1410.               WinSendMsg( hdrwin, WM_USER, (MPARAM) STOP_READING, NULL );
  1411.               break;
  1412.            case VK_TAB:
  1413.               WinSendMsg( hdrwin, WM_USER, (MPARAM) NEXT_UNREAD, NULL );
  1414.               break;
  1415.            case VK_BACKTAB:
  1416.               break;
  1417.            }
  1418.          }
  1419.  
  1420.       break;
  1421.       }
  1422.  
  1423.  
  1424.     /* handle requests from utility task */
  1425.     case WM_USER: {
  1426.  
  1427.       char  buf[80];
  1428.  
  1429.       switch ( (ULONG)mp1 )
  1430.         {
  1431.         /* put the focus here */
  1432.         case ART_FOCUS:
  1433.              WinSetFocus( HWND_DESKTOP, hwnd );
  1434.              break;
  1435.  
  1436.         case MAIL_VERIFY: {
  1437.           sprintf(buf, "Send message to %s? ", (char *)mp2 );
  1438.           queryans =
  1439.             message(buf, "Which?", MB_YESNO );
  1440.           DosPostEventSem( work_to_do );
  1441.           break;
  1442.           }
  1443.         case POST_VERIFY: {
  1444.           queryans =
  1445.             message("Post article?", "Which?", MB_YESNO );
  1446.           DosPostEventSem( work_to_do );
  1447.           break;
  1448.           }
  1449.         case MAIL_FILERR: {
  1450.           message("*** Cannot open temp file ***", "Sorry", MB_CANCEL );
  1451.           break;
  1452.           }
  1453.         case REPART_QUOTE: {
  1454.           queryans = message("Quote article? ", "Which?", MB_YESNO );
  1455.           DosPostEventSem( work_to_do );
  1456.           break;
  1457.           }
  1458.  
  1459.         case WE_CANCELLED: {
  1460.           break;
  1461.           }
  1462.  
  1463.         case MAIL_ARTICLE: {
  1464.          if ( strlen(recipient) > 1 )
  1465.             {
  1466.             DO_UTIL( MAIL );
  1467.             }
  1468.           break;
  1469.           }
  1470.  
  1471.         case POST_ARTICLE: {
  1472.  
  1473.           /* validate group */
  1474.           if ( !check_valid_post_group( ngroup ) )
  1475.              {
  1476.              message( "Invalid Newsgroup!", "Sorry", MB_CANCEL );
  1477.              break;
  1478.              }
  1479.           if ( tx != NULL )
  1480.              {
  1481.              if ( currfunc != IDM_NEWPOST )
  1482.                 quotans = message( "Quote Article?", "Which?", MB_YESNO );
  1483.              else
  1484.                 quotans = MBID_NO;
  1485.              DO_UTIL( POST_EDIT );
  1486.              }
  1487.           break;
  1488.           }
  1489.         }
  1490.       break;
  1491.       }
  1492.  
  1493.  
  1494.     case WM_VSCROLL: {
  1495.       BOOL paint;
  1496.       USHORT cntln, ix;
  1497.       aLINE  *orig;
  1498.  
  1499.       paint = TRUE;
  1500.       orig = topline;
  1501.  
  1502.       switch ( SHORT2FROMMP(mp2) )
  1503.          {
  1504.          case SB_LINEUP:
  1505.               if ( topline != tx->top )
  1506.                  topline = topline->last;
  1507.               break;
  1508.  
  1509.          case SB_PAGEUP:
  1510.               cntln = (cyClient / linehite) - 1;
  1511.               for ( ix = 0; ix < cntln; ix++ )
  1512.                   {
  1513.                   if ( topline != tx->top )
  1514.                      topline = topline->last;
  1515.                   else break;
  1516.                   }
  1517.  
  1518.               break;
  1519.  
  1520.          case SB_SLIDERTRACK:
  1521.               break;
  1522.  
  1523.          case SB_SLIDERPOSITION:
  1524.               cntln = SHORT1FROMMR( WinSendMsg( hwndScroll, SBM_QUERYPOS,
  1525.                                     NULL, NULL ) );
  1526.               topline = tx->top;
  1527.               for ( ix = 1; ix < cntln; ix++ )
  1528.                   if ( topline->next != NULL )
  1529.                      topline = topline->next;
  1530.  
  1531.               break;
  1532.  
  1533.          case SB_PAGEDOWN:
  1534.               cntln = (cyClient / linehite) - 1;
  1535.               for ( ix = 0; ix < cntln; ix++ )
  1536.                   {
  1537.                   if ( topline->next != NULL )
  1538.                      topline = topline->next;
  1539.                   else break;
  1540.                   }
  1541.               break;
  1542.  
  1543.          case SB_LINEDOWN:
  1544.               if ( topline->next != NULL )
  1545.                  topline = topline->next;
  1546.               break;
  1547.  
  1548.          case SB_ENDSCROLL:
  1549.               paint = FALSE;
  1550.               break;
  1551.  
  1552.          }
  1553.  
  1554.       if ( paint && topline != orig )
  1555.          {
  1556.          cntln = ( 100 * topline->index ) / tx->lines;
  1557.          WinSendMsg( hwndScroll, SBM_SETPOS, MPFROMSHORT( cntln ), NULL );
  1558.          WinInvalidateRect (hwnd, NULL, FALSE);
  1559.          }
  1560.  
  1561.       break;
  1562.       }
  1563.  
  1564.     case WM_ERASEBACKGROUND:
  1565.       /******************************************************************/
  1566.       /* Return TRUE to request PM to paint the window background       */
  1567.       /* in SYSCLR_WINDOW.                                              */
  1568.       /******************************************************************/
  1569.       return (MRESULT)( TRUE );
  1570.  
  1571.     case WM_PAINT:
  1572.       /******************************************************************/
  1573.       /* Window contents are drawn here in WM_PAINT processing.         */
  1574.       /******************************************************************/
  1575.       {
  1576.       RECTL  rc;                        /* Rectangle coordinates        */
  1577.       POINTL pt;                        /* String screen coordinates    */
  1578.       aLINE  *lnp;
  1579.       int    sLen;
  1580.  
  1581.       hps = WinBeginPaint (hwnd, (HPS)0L, &rc);
  1582.       GpiQueryFontMetrics( hps, sizeof fm, &fm );
  1583.       linehite  =  fm.lMaxBaselineExt + (fm.lMaxDescender/2);
  1584.       WinSendMsg( hwndScroll, SBM_SETTHUMBSIZE,
  1585.                   MPFROM2SHORT( (cyClient / linehite), tx->lines ), 0L );
  1586.  
  1587.       GpiErase( hps );
  1588.       lnp = topline;
  1589.  
  1590.       /* write as many lines from topline as will fit in current window */
  1591.       pt.x = fm.lAveCharWidth;
  1592.       pt.y = cyClient;
  1593.       lcnt = 0;
  1594.  
  1595.       while ( ( pt.y -= linehite ) > 0
  1596.                 && lnp != NULL )
  1597.             {
  1598.             sLen = strlen( lnp->data );
  1599.             if ( lnp->data[ sLen - 1 ] == '\n' ) sLen--;
  1600.             if ( sLen > 0 )
  1601.                {
  1602.                lcnt++;
  1603.                GpiCharStringAt( hps, &pt, sLen, lnp->data );
  1604.                }
  1605.             lnp = lnp->next;
  1606.             }
  1607.  
  1608.       WinEndPaint( hps );                      /* Drawing is complete   */
  1609.       break;
  1610.       }
  1611.  
  1612.     case WM_CLOSE: {
  1613.       /******************************************************************/
  1614.       /* This is the place to put your termination routines             */
  1615.       /******************************************************************/
  1616.       WinSendMsg( hdrwin, WM_USER, (MPARAM) STOP_READING, NULL );
  1617.       break;
  1618.       }
  1619.  
  1620.     case WM_DESTROY: {
  1621.       SWP  lastpos;
  1622.       if ( !WinQueryWindowPos( hwndArt, &lastpos ) )
  1623.          AbortSN( hwndFrame, hwndClient, 21 );
  1624.       artloc.artx = (USHORT)lastpos.x;
  1625.       artloc.arty = (USHORT)lastpos.y;
  1626.       artloc.artwidth  = (USHORT)lastpos.cx;
  1627.       artloc.artheight = (USHORT)lastpos.cy;
  1628.       return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  1629.       }
  1630.  
  1631.  
  1632.     default:
  1633.       /******************************************************************/
  1634.       /* Everything else comes here.  This call MUST exist              */
  1635.       /* in your window procedure.                                      */
  1636.       /******************************************************************/
  1637.  
  1638.       return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  1639.   }
  1640.  
  1641.   return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  1642. } /* End of ArticleProc */
  1643.  
  1644.  
  1645. /* utililty task for long-running functions, one at a time
  1646.    schedule only ONE function */
  1647.  
  1648. void util_task( void * parm )
  1649. {
  1650. ULONG postct;   /* post count, not used  */
  1651. APIRET rc;
  1652. FILE  *fp;      /* utility file */
  1653.  
  1654.   DosOpenEventSem( NULL, &work_to_do );
  1655.  
  1656.   do
  1657.     {
  1658.  
  1659.     /* wait on a work item */
  1660.     rc = DosWaitEventSem( work_to_do, -1L );
  1661.  
  1662.     /* clear semaphore */
  1663.     rc = DosResetEventSem( work_to_do, &postct );
  1664.     if ( rc )
  1665.        AbortSN( hwndFrame, hwndClient, 23 );
  1666.  
  1667.     switch ( util_func )
  1668.       {
  1669.  
  1670.       case MAIL: {
  1671.          mail_to_someone( tx, recipient );
  1672.          break;
  1673.          }
  1674.  
  1675.       case REPART: {
  1676.          reply_to_article( tx );
  1677.          break;
  1678.          }
  1679.  
  1680.       case PRINT: {
  1681.          /* print the current article */
  1682.          fp = fopen( "LPT1", "w" );
  1683.          if ( fp != NULL )
  1684.             copy_article_out( fp, tx );
  1685.          break;
  1686.          }
  1687.  
  1688.       case POST_EDIT: {
  1689.          post_art( quotans );
  1690.          fprintf(errf, "returned from post_edit\n" );
  1691.          break;
  1692.          }
  1693.  
  1694.       case SEARCH:    {
  1695.          ARTICLE *  rp;
  1696.          rp = search_group( gp, Srchstr );
  1697.          if ( rp != NULL )
  1698.             {
  1699.             /* post message to Glistproc to display the
  1700.                given threads */
  1701.             artlist = rp;
  1702.             WinPostMsg( hwndFrame, WM_USER, (MPARAM) DISP_LIST, MPFROMP( rp ) );
  1703.             }
  1704.          else
  1705.             {
  1706.             /* post message to say nothing found */
  1707.             WinPostMsg( hwndFrame, WM_USER, (MPARAM) MAIL_FILERR,
  1708.                         MPFROMP( "Unable to locate string" ) );
  1709.             }
  1710.          break;
  1711.          }
  1712.  
  1713.       case SAVED: {
  1714.          /* save the current article */
  1715.          fp = fopen( savepath, "w" );
  1716.          if ( fp != NULL )
  1717.             copy_article_out( fp, tx );
  1718.          break;
  1719.          }
  1720.  
  1721.       }
  1722.  
  1723.       if ( util_func != EOJ )
  1724.          util_func = TASK_FREE; /* mark available */
  1725.  
  1726.     }  while ( util_func != EOJ );
  1727.  
  1728. }
  1729.  
  1730.  
  1731. /*------------------------------- main --------------------------------*/
  1732.  
  1733. int  main(void)
  1734. {
  1735.   HMQ  hmq;                             /* Message queue handle         */
  1736.   QMSG qmsg;                            /* Message from message queue   */
  1737.   ULONG lsize;                          /* profile size query output    */
  1738.   SWP   wpos;                           /* group window position */
  1739.  
  1740.  
  1741.   /* open the debug file */
  1742.   errf = fopen( "pmnews.err" ,"w" );
  1743.  
  1744.  
  1745.  
  1746.   if ((hab = WinInitialize(0)) == 0L) /* Initialize PM     */
  1747.      AbortSN(hwndFrame, hwndClient, 1 ); /* Terminate the application    */
  1748.  
  1749.  
  1750.  
  1751.  
  1752.   if ((hmq = WinCreateMsgQueue( hab, 0 )) == 0L)/* Create a msg queue */
  1753.      AbortSN(hwndFrame, hwndClient, 2 ); /* Terminate the application    */
  1754.  
  1755.   if (!WinRegisterClass(                /* Register window class        */
  1756.      hab,                               /* Anchor block handle          */
  1757.      PMNEWS_CLASS,                      /* Window class name            */
  1758.      (PFNWP)ArticleProc,                /* Address of window procedure  */
  1759.      CS_SIZEREDRAW,                     /* Class style                  */
  1760.      0                                  /* No extra window words        */
  1761.      ))
  1762.      AbortSN(hwndFrame, hwndClient, 4 ); /* Terminate the application    */
  1763.  
  1764.   /* start the utility thread */
  1765.   DosCreateEventSem( NULL, &work_to_do, DC_SEM_SHARED, 0 );
  1766.   DosCreateEventSem( NULL, &eojsem, 0, 0 );
  1767.  
  1768.   util_thread = _beginthread( util_task, NULL, 16384, NULL );
  1769.   if ( util_thread < 0 )
  1770.      {
  1771.      AbortSN(hwndFrame, hwndClient, 11 ); /* Terminate the application    */
  1772.      }
  1773.  
  1774.  
  1775.   hwndFrame = WinLoadDlg( HWND_DESKTOP, HWND_DESKTOP,
  1776.                             (PFNWP) GListProc,
  1777.                             (HMODULE)0L, IDD_GLIST,
  1778.                             NULL );
  1779.  
  1780. /************************************************************************/
  1781. /* Get and dispatch messages from the application message queue         */
  1782. /* until WinGetMsg returns FALSE, indicating a WM_QUIT message.         */
  1783. /************************************************************************/
  1784.  
  1785.  
  1786.   if ( hwndFrame != (HWND)0L )
  1787.      {
  1788.      if ( ( init = PrfOpenProfile( hab, "pmnews.ini" ) )  == (HINI)0L )
  1789.         {
  1790.         message( "Unable to open pmnews.ini", "Sorry", MB_CANCEL );
  1791.         }
  1792.      else
  1793.         {
  1794.         /* load .ini data */
  1795.         PrfQueryProfileSize( init, "Article", "artloc", &lsize );
  1796.         if ( lsize == sizeof(artloc) )
  1797.            {
  1798.            PrfQueryProfileData( init, "Article", "artloc", &artloc, &lsize );
  1799.            if ( !( artloc.artx | artloc.arty | artloc.artheight | artloc.artwidth ) )
  1800.               {
  1801.               artloc.artx = ARTX;
  1802.               artloc.arty = ARTY;
  1803.               artloc.artwidth = ARTWIDTH;
  1804.               artloc.artheight = ARTHEIGHT;
  1805.               }
  1806.            WinSetWindowPos( hwndFrame, HWND_TOP,
  1807.                     artloc.grpx, artloc.grpy, 0, 0,
  1808.                     SWP_ZORDER | SWP_MOVE );
  1809.            }
  1810.  
  1811.         while( WinGetMsg( hab, &qmsg, 0L, 0, 0 ) )
  1812.             WinDispatchMsg( hab, &qmsg );
  1813.  
  1814.         if ( WinQueryWindowPos( hwndFrame, &wpos ) )
  1815.            {
  1816.            artloc.grpx = wpos.x;
  1817.            artloc.grpy  = wpos.y;
  1818.            }
  1819.  
  1820.         PrfWriteProfileData( init,
  1821.           "Article", "artloc", &artloc, sizeof(artloc) );
  1822.         PrfCloseProfile( init );
  1823.         }
  1824.  
  1825.      WinDestroyWindow(hwndFrame);        /* Tidy up...                   */
  1826.      }
  1827.   else logWinErr();
  1828.  
  1829.  
  1830.   /* tell the utility task to go away */
  1831.   util_func = EOJ;
  1832.   DosPostEventSem( work_to_do );
  1833.  
  1834.  
  1835.   WinDestroyMsgQueue( hmq );             /* Tidy up...                   */
  1836.   WinTerminate( hab );                   /* Terminate the application    */
  1837.  
  1838.  
  1839.   fclose( errf );   /* close the debug file */
  1840.  
  1841.   return 0;
  1842.  
  1843. } /* End of main */
  1844.  
  1845.