/*-- WVUTIL.C -- File containing utility routines.
 */

#include "windows.h"
#include "wvglob.h"
#include "winvn.h"
#ifndef MAC
#include "winundoc.h"
#include <ctype.h>
#endif

/* temporary test */
char far *mylstrcpy(char *ptr1, char *ptr2);
char * get_xhdr_line (char * line);
char * parse_usenet_date (char * date);

/*--- function GetNum --------------------------------------------
 *
 *  Cracks off a positive integer number from a string.
 *
 *  Entry    *ptr  is the character position to start scanning
 *                 for an integer
 *
 *  Exit     *ptr  is the character position at which we stopped
 *                 scanning (because of a non-digit).
 *           *num  is the cracked off number.
 *           Returns TRUE iff we got a number.
 */
BOOL
GetNum(ptr,num)
char **ptr;
long int *num;
{
   BOOL gotit = FALSE;

   /* Skip initial spaces                                            */

   while((**ptr) && **ptr == ' ') (*ptr)++;

   *num = 0;
   while(**ptr && isdigit(**ptr)) {
      *num = 10*(*num) + (**ptr - '0');
      gotit = TRUE;
      (*ptr)++;
   }
   return(gotit);
}

char * get_xhdr_line (char *line)
{
  char * cptr;
/* skip past the art # and space */
  for(cptr=line; isdigit(*cptr); cptr++);
  for(;*cptr == ' ';cptr++);
  return (cptr);
}

/*-- function StrToRGB -------------------------------------------------
 *
 *  Takes an ASCII string of the form "r,g,b" where r, g, and b are
 *  decimal ASCII numbers, and converts it to an RGB color number.
 */
DWORD
StrToRGB(cstring)
char *cstring;
{
   BYTE red, green, blue;
   long int lred, lgreen, lblue;

   GetNum(&cstring,&lred);
   cstring++;
   GetNum(&cstring,&lgreen);
   cstring++;
   GetNum(&cstring,&lblue);
   red = (BYTE) lred; green = (BYTE) lgreen; blue = (BYTE) lblue;
#ifndef MAC
   return(RGB(red,green,blue));
#else
   return((DWORD) red+green+blue);
#endif
}

/* This was lifted from ANU news. */

char *
parse_usenet_date(char * s)
{
  char *cp, mon[80], pdate[15];
  int dom = 0, yr = 0, hr = 0, mn = 0, sc = 0, cvttime;

  if (!s || !*s) return(0);
  if (cp = strchr(s,',')) s = ++cp;
  while (isspace(*s)) s++;
  *mon = '\0';
  if (isdigit(*s)) {
    sscanf(s,"%d %s %d %d:%d:%d",&dom,mon,&yr,&hr,&mn,&sc);
    if (yr < 100 ) yr += 1900;
    }
  else sscanf(s,"%*s %s %d %d:%d:%d %d",mon,&dom,&hr,&mn,&sc,&yr);

  if (!dom || !yr || !*(cp = mon)) return(0);
  if ((dom <= 0) || (dom >= 32)) return(0);
  if ((yr < 1980) || (yr > 2020)) return(0);
  if (strlen(mon) > 10) return(0);
  if ((hr < 0) || (hr > 23)) return(0);
  if ((mn < 0) || (mn > 59)) return(0);
  if ((sc < 0) || (sc > 59)) return(0);

/*  while (*cp) { *cp = toupper(*cp); ++cp; } */
/*  sprintf(s,"%d-%s-%d %d:%d:%d",dom,mon,yr,hr,mn,sc); */
  sprintf(s,"%s %2.2d",mon,dom);
  return(s);
}


/*-- function DoCommInput ---------------------------------------
 *
 *
 */
void
DoCommInput()
{
   int ch;

   while((ch = MRRReadComm()) >= 0) {
      /*   putchar(ch); */  /* debug */
      if(ch == IgnoreCommCh) {
      } else if(ch == EOLCommCh) {
         *CommLinePtr = '\0';
         DoCommState();
         CommLinePtr = CommLineIn;
      } else {
         *(CommLinePtr++) = (char) ch;
         if(CommLinePtr == CommLineLWAp1) CommLinePtr--;
      }
   }
}

/*-- function DoCommState ----------------------------------------------
 *
 *  Function to implement an FSA to process incoming lines from
 *  the server.
 *  This function is called once for each line from the server.
 *
 *    Entry    CommLineIn  is a zero-terminated line received from
 *                         the server.
 *             CommState   is the current state of the FSA.
 */
void
DoCommState()
{
   TypLine far *LinePtr;
   TypBlock far *BlockPtr;
   TypArticle *artptr;
   TypArticle far *MyArtPtr;
   HANDLE hBlock;
   HWND hWndPostEdit;
   unsigned int Offset;
   TypLineID MyLineID;
   int retcode;
   int ih, found;
   unsigned int estnum;
   long int first,last;
   long int artnum;
   int lineord;
   int mylen;
   int col;
   int mbcode;
   BOOL done=FALSE;
   BOOL dolist;
   char group[MAXINTERNALLINE];
   char mybuf[MAXINTERNALLINE];
   char artline[MAXINTERNALLINE];
   char scanline[MAXINTERNALLINE];
   char *cptr, *cdest;
   char far *lpsz;
   char indicator;
   HDC hDC;
   long int PrevHighArt;
   HANDLE header_handle;
   TypHeader * headers;
   TypGroup far * GroupDoc;
   long int OldHighestSeen;

   if(CommDoc) {

      switch(CommState) {
         case ST_NONE:
            break;

         case ST_ESTABLISH_COMM:
            retcode = 0;
            sscanf(CommLineIn,"%u",&retcode);
            if(retcode == 200 || retcode == 201) {/* was 500 from induced error */
               dolist = DoList;
               if(dolist == ID_DOLIST_ASK-ID_DOLIST_BASE) {
                  dolist = DialogBox(hInst,"WinVnDoList",hWndConf,lpfnWinVnDoListDlg);
               }
               if(dolist) {
                  StartList();
               } else {
                  CommState = ST_NONE;
                  CommBusy = FALSE;
                  Initializing = INIT_DONE;
               }

               InvalidateRect(hWndConf,NULL,FALSE);
            }
	    else {
	    	MessageBox (hWndConf, CommLineIn, "Error", MB_OK | MB_ICONHAND);
		MRRCloseComm ();
		PostQuitMessage (0);
	    }

            break;

         case ST_LIST_RESP:
            retcode = 0;
            sscanf(CommLineIn,"%d",&retcode);
            if(retcode != 215) break;
            CommState = ST_LIST_GROUPLINE;
            RcvLineCount = 0;
            break;

         case ST_LIST_GROUPLINE:
            if(strcmp(CommLineIn,".") == 0) {
               CommState = ST_NONE;
               CommBusy = FALSE;
               Initializing = INIT_DONE;
               InvalidateRect(hWndConf,NULL,FALSE);

               ProcEndList();
            } else {
               ProcListLine((unsigned char *)CommLineIn);
            }
            break;

         case ST_GROUP_RESP:
            retcode = 0;
            sscanf(CommLineIn,"%u %u %ld %ld %s",&retcode,&estnum,&first,&last,group);
	    if (retcode == 415) {
	    	MessageBox (hWndConf, "No Such Newsgroup", "Error", MB_OK | MB_ICONHAND);
	    	CommBusy = FALSE;
	    	CommState = ST_NONE;
		break;
	    }
            if(retcode < 100) break;

      	LockLine(CommDoc->hParentBlock,CommDoc->ParentOffset,CommDoc->ParentLineID,&BlockPtr,&LinePtr);

      	if (estnum > 0)
      	{
      	header_handle = GlobalAlloc (GMEM_MOVEABLE, (long)((sizeof (TypHeader)) * (long)(estnum)) + sizeof (char *));  /* How risky is this? */
        (((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->header_handle) = header_handle;
      	}

            (((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->ServerEstNum) = estnum;
            (((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->ServerFirst ) = first;
            (((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->ServerLast  ) = last;
            GlobalUnlock(BlockPtr->hCurBlock);

            mylen = sprintf(mybuf,"XHDR from %ld-%ld\r",first,999999L);
            PutCommLine(mybuf,mylen);
            CommState = ST_XHDR_FROM_START;

            break;

      	case ST_XHDR_FROM_START:
            retcode = 0;
            sscanf(CommLineIn,"%d",&retcode);
            if(retcode < 100) break;
            CommState = ST_XHDR_FROM_DATA;
	    CommDoc->ActiveLines = 0;
	    break;

	case ST_XHDR_FROM_DATA:
            if(strcmp(CommLineIn,".") == 0) {
               	LockLine(CommDoc->hParentBlock,CommDoc->ParentOffset,CommDoc->ParentLineID,&BlockPtr,&LinePtr);
                (((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->total_headers) = CommDoc->ActiveLines;
		first = (((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->ServerFirst );
            	GlobalUnlock(BlockPtr->hCurBlock);
		CommDoc->ActiveLines = 0;

		/* Now ask for the date lines */
                mylen = sprintf(mybuf,"XHDR date %ld-%ld\r",first,999999L);
                PutCommLine(mybuf,mylen);
                CommState = ST_XHDR_DATE_START;
            }
            else {
		/* Access the Group struct, get HANDLE for header data */
               	LockLine(CommDoc->hParentBlock,CommDoc->ParentOffset,CommDoc->ParentLineID,&BlockPtr,&LinePtr);
                header_handle = ((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->header_handle;
            	GlobalUnlock(BlockPtr->hCurBlock);

		/* Lock the header data */
            	headers = (TypHeader *) ((char *) GlobalLock (header_handle) + sizeof(char *));

		sscanf (CommLineIn, "%ld", &artnum);
            	headers[CommDoc->ActiveLines].number = artnum;

            	mylstrcpy(headers[CommDoc->ActiveLines].from,
                          (char far *) get_xhdr_line (CommLineIn));

		GlobalUnlock (header_handle);
            	CommDoc->ActiveLines++;

            }

	    break;

      	case ST_XHDR_DATE_START:
            retcode = 0;
            sscanf(CommLineIn,"%d",&retcode);
            if(retcode < 100) break;
            CommState = ST_XHDR_DATE_DATA;
	    CommDoc->ActiveLines = 0;
	    break;

	case ST_XHDR_DATE_DATA:
            if(strcmp(CommLineIn,".") == 0) {
               	LockLine(CommDoc->hParentBlock,CommDoc->ParentOffset,CommDoc->ParentLineID,&BlockPtr,&LinePtr);
                (((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->total_headers) = CommDoc->ActiveLines;
		first = (((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->ServerFirst );
            	GlobalUnlock(BlockPtr->hCurBlock);
		CommDoc->ActiveLines = 0;

		/* Now ask for the #of lines */
                mylen = sprintf(mybuf,"XHDR lines %ld-%ld\r",first,999999L); 
                PutCommLine(mybuf,mylen);
                CommState = ST_XHDR_LINES_START; 
            }
            else {
		/* Access the Group struct, get HANDLE for header data */
               	LockLine(CommDoc->hParentBlock,CommDoc->ParentOffset,CommDoc->ParentLineID,&BlockPtr,&LinePtr);
                header_handle = ((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->header_handle;
            	GlobalUnlock(BlockPtr->hCurBlock);

		/* Lock the header data */
            	headers = (TypHeader *)((char *) GlobalLock (header_handle) + sizeof (char *));

            	mylstrcpy(headers[CommDoc->ActiveLines].date,
                          (char far *) (parse_usenet_date (get_xhdr_line (CommLineIn))));

		GlobalUnlock (header_handle);
            	CommDoc->ActiveLines++;

            }

	    break;

      	case ST_XHDR_LINES_START:
            retcode = 0;
            sscanf(CommLineIn,"%d",&retcode);
            if(retcode < 100) break;
            CommState = ST_XHDR_LINES_DATA;
	    CommDoc->ActiveLines = 0;
	    break;

	case ST_XHDR_LINES_DATA:
            if(strcmp(CommLineIn,".") == 0) {
               	LockLine(CommDoc->hParentBlock,CommDoc->ParentOffset,CommDoc->ParentLineID,&BlockPtr,&LinePtr);
                (((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->total_headers) = CommDoc->ActiveLines;
		first = (((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->ServerFirst );
            	GlobalUnlock(BlockPtr->hCurBlock);
		CommDoc->ActiveLines = 0;

		/* Now ask for the subject headers */
                mylen = sprintf(mybuf,"XHDR subject %ld-%ld\r",first,999999L); 
                PutCommLine(mybuf,mylen);
                CommState = ST_XHDR_RESP; 
            }
            else {
		/* Access the Group struct, get HANDLE for header data */
               	LockLine(CommDoc->hParentBlock,CommDoc->ParentOffset,CommDoc->ParentLineID,&BlockPtr,&LinePtr);
                header_handle = ((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->header_handle;
            	GlobalUnlock(BlockPtr->hCurBlock);

		/* Lock the header data */
            	headers = (TypHeader *)((char *) GlobalLock (header_handle) + sizeof (char *));

		sscanf (CommLineIn, "%ld %Fd", &artnum, &(headers[CommDoc->ActiveLines].lines));

		GlobalUnlock (header_handle);
            	CommDoc->ActiveLines++;

            }

	    break;

      	case ST_XHDR_REF_START:
            retcode = 0;
            sscanf(CommLineIn,"%d",&retcode);
            if(retcode < 100) break;
            CommState = ST_XHDR_REF_DATA;
	    CommDoc->ActiveLines = 0;
	    break;

	case ST_XHDR_REF_DATA:
            if(strcmp(CommLineIn,".") == 0) {
               	LockLine(CommDoc->hParentBlock,CommDoc->ParentOffset,CommDoc->ParentLineID,&BlockPtr,&LinePtr);
                (((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->total_headers) = CommDoc->ActiveLines;
		first = (((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->ServerFirst );
            	GlobalUnlock(BlockPtr->hCurBlock);
		CommDoc->ActiveLines = 0;

		/* Now ask for the subject lines */
                mylen = sprintf(mybuf,"XHDR subject %ld-%ld\r",first,999999L);
                PutCommLine(mybuf,mylen);
                CommState = ST_XHDR_RESP;
            }
            else {
		/* Access the Group struct, get HANDLE for header data */
               	LockLine(CommDoc->hParentBlock,CommDoc->ParentOffset,CommDoc->ParentLineID,&BlockPtr,&LinePtr);
                header_handle = ((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->header_handle;
            	GlobalUnlock(BlockPtr->hCurBlock);

		/* Lock the header data */
            	headers = (TypHeader *)((char *) GlobalLock (header_handle) + sizeof (char *));

            	mylstrncpy(headers[CommDoc->ActiveLines].references,
                          (char far *) (get_xhdr_line (CommLineIn)),
                           30);		/* bad, hardcoded. */

		GlobalUnlock (header_handle);
            	CommDoc->ActiveLines++;

            }

	    break;

         case ST_XHDR_RESP:
            retcode = 0;
            sscanf(CommLineIn,"%d",&retcode);
            if(retcode < 100) break;
            CommState = ST_XHDR_SUBJ;
            break;

         case ST_XHDR_SUBJ:
            if(strcmp(CommLineIn,".") == 0) {
               CommState = ST_IN_GROUP;
               CommBusy = FALSE;

		/* release the mouse that is captured to the usenet window */
		ReleaseCapture ();

		CommDoc->ActiveLines = 0;
               /* Fetch this group's line in NetDoc so we can get the
                * group's name for the window's title bar.
                */
               LockLine(CommDoc->hParentBlock,CommDoc->ParentOffset,CommDoc->ParentLineID,&BlockPtr,&LinePtr);
               lpsz = (char far *) ( ((char far *)LinePtr) +
                sizeof(TypLine)+ sizeof(TypGroup) ) ;
               mylstrncpy(group,lpsz,MAXGROUPNAME);
               sprintf(mybuf,"%s (%u articles)",group,CommDoc->TotalLines);
               SetWindowText(CommDoc->hDocWnd,mybuf);

               /* If we have information from NEWSRC on the highest-
                * numbered article previously seen, position the window
                * so the new articles can be seen without scrolling.
                */

            	/* reinsert this code */

            	InvalidateRect(CommDoc->hDocWnd,NULL,FALSE);
            } else {

               artnum = 0;
               sscanf(CommLineIn,"%ld",&artnum);
               if(artnum) {
                LockLine(CommDoc->hParentBlock,CommDoc->ParentOffset,CommDoc->ParentLineID,&BlockPtr,&LinePtr);

		/* inside the lock, can access the GroupStruct */
                header_handle = ((TypGroup far *) ((char far *) LinePtr + sizeof(TypLine)) )->header_handle;
               	headers = (TypHeader *) ((char *) GlobalLock (header_handle) + sizeof(char *)) ;

		/* update the seen thing. */

                headers[CommDoc->ActiveLines].Selected= FALSE ;
                headers[CommDoc->ActiveLines].ArtDoc  = (TypDoc *) NULL;
		headers[CommDoc->ActiveLines].Seen =
		   WasArtSeen (artnum,(TypGroup far *)( ((char far *)LinePtr) + sizeof(TypLine) ) );

                UnlockLine(BlockPtr,LinePtr,&(CommDoc->hParentBlock),&(CommDoc->ParentOffset),&(CommDoc->ParentLineID));

            	mylstrcpy(headers[CommDoc->ActiveLines].subject,
                          get_xhdr_line (CommLineIn));

		GlobalUnlock (header_handle);

		CommDoc->ActiveLines++;

		CommDoc->TotalLines = CommDoc->ActiveLines;

                /* Cause the window to be repainted.
                 * Also, every UPDATE_TITLE_FREQ lines, update the
                 * window title to let the user know how far we
                 * have gotten.
                 */
                InvalidateRect(CommDoc->hDocWnd,NULL,FALSE);
                if((++RcvLineCount)%UPDATE_TITLE_FREQ == 0) {
                   sprintf(mybuf,"Retrieving %uth article of ",RcvLineCount);
                   LockLine(CommDoc->hParentBlock,CommDoc->ParentOffset,CommDoc->ParentLineID,&BlockPtr,&LinePtr);
                   lpsz = (char far *) ( ((char far *)LinePtr) +
                    sizeof(TypLine)+ sizeof(TypGroup) ) ;
                   lstrcat(mybuf,lpsz);
                   SetWindowText(CommDoc->hDocWnd,mybuf);
                   GlobalUnlock(BlockPtr->hCurBlock);
               /*
                *  if(++TimesWndUpdated <= MAX_IMMEDIATE_UPDATE) {
                *     InvalidateRect(CommDoc->hDocWnd,NULL,FALSE);
                *  }
                */
                   UpdateWindow(CommDoc->hDocWnd);
                }
             }
          }

          break;

         case ST_IN_GROUP:
            break;

         case ST_ARTICLE_RESP:
            retcode = 0;
            sscanf(CommLineIn,"%d",&retcode);
            if(retcode < 100) break;
            CommState = ST_REC_ARTICLE;
            break;

         case ST_REC_ARTICLE:
            if(strcmp(CommLineIn,".") == 0) {
               CommState = ST_IN_GROUP;
               CommBusy = FALSE;

            	LockLine (CommDoc->ParentDoc->hParentBlock,
            	          CommDoc->ParentDoc->ParentOffset,
            	          CommDoc->ParentDoc->ParentLineID,
            	          &BlockPtr, &LinePtr);

            	GroupDoc = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));

            	header_handle = GroupDoc->header_handle;
            	headers = (TypHeader *) ((char *) GlobalLock (header_handle) + sizeof(char *)) ;

		lpsz = (char far *) headers[CommDoc->LastSeenLineID].subject;

		GlobalUnlock (header_handle);
               mylstrncpy(group,lpsz,MAXGROUPNAME);
               sprintf(mybuf,"%s (%u lines)",group,CommDoc->TotalLines);
               SetWindowText(CommDoc->hDocWnd,mybuf);
               InvalidateRect(CommDoc->hDocWnd,NULL,FALSE);
               GlobalUnlock(BlockPtr->hCurBlock);

               /* Skip to the first line of the text of the article
                * and make sure it's visible on the screen.  This is
                * so that the user doesn't have to have the first
                * screen filled with a lengthy, worthless header.
                */
               if(CommDoc->TotalLines > CommDoc->ScYLines
                 && !CommDoc->TopScLineID) {
                  TopOfDoc(CommDoc,&BlockPtr,&LinePtr);
                  found = FALSE;
                  do {
                     lpsz = ((char far *)LinePtr + sizeof(TypLine) + sizeof(TypText));
                     if(IsLineBlank(lpsz)) {
                        found = TRUE;
                        break;
                     }
                     if(!NextLine(&BlockPtr,&LinePtr)) break;
                  } while(!found);
                  NextLine(&BlockPtr,&LinePtr);

                  /* If the line is in the last screen's worth of lines, back
                   * up the pointer so it points to the first line of the last
                   * screen.
                   */
                  if(found) {
                     AdjustTopSc(BlockPtr,LinePtr);
                  } else {
                     UnlockLine(BlockPtr,LinePtr,&hBlock,&Offset,&MyLineID);
                  }
               }

            } else {
               /* Copy this line into an image of a textblock line,
                * expanding tabs.
                */
               cdest = artline+sizeof(TypLine)+sizeof(TypText);
               for(col=0,cptr=CommLineIn; *cptr &&
                col<(MAXINTERNALLINE-3*sizeof(TypLine)-sizeof(TypText)); cptr++) {
                  if(*cptr == '\t') {
                     do {
                        *(cdest++) = ' ';
                     } while (++col & 7);
                  } else {
                     *(cdest++) = *cptr;
                     col++;
                  }
               }
               *(cdest++) = '\0';

               mylen = (cdest-artline) + sizeof(int);
               mylen += mylen%2;
               ((TypText *)(artline+sizeof(TypLine)))->NameLen =
                (cdest-1) - (artline+sizeof(TypLine)+sizeof(TypText));
               ((TypLine *)artline)->length = mylen;
               ((TypLine *)artline)->LineID = NextLineID++;
               *( (int *) (artline+mylen-sizeof(int)) ) = mylen;
               LockLine(CommDoc->hCurAddBlock,CommDoc->AddOffset,CommDoc->AddLineID,&BlockPtr,&LinePtr);
               AddLine((TypLine *)artline,&BlockPtr,&LinePtr);
               UnlockLine(BlockPtr,LinePtr,&(CommDoc->hCurAddBlock),
                &(CommDoc->AddOffset),&(CommDoc->AddLineID));
               if((CommDoc->TotalLines % UPDATE_ART_FREQ) == 0) {
            InvalidateRect(CommDoc->hDocWnd,NULL,FALSE);  
               }
            }

            break;

         case ST_POST_WAIT_PERMISSION:
            for(ih=0,found=FALSE; !found && ih<MAXPOSTWNDS; ih++) {
              if(&(PostingDocs[ih]) == CommDoc) {
#ifndef MAC
                 hWndPostEdit = hWndPostEdits[ih];
#else
  /* mrr add here */
#endif
                 found = TRUE;
                 break;
              }
            }
            retcode = 0;
            sscanf(CommLineIn,"%d",&retcode);
            if(retcode <= 0) {
               break;
            } else if(retcode == 340) {
               PostText(ih,DOCTYPE_POSTING);
            } else {
               MessageBox(hWndPostEdit,CommLineIn+4,"Cannot Post Article",
                  MB_OK|MB_ICONEXCLAMATION);
               CommBusy = FALSE;
               CommState = ST_NONE;
            }

            break;

         case ST_POST_WAIT_END:
            for(ih=0,found=FALSE; !found && ih<MAXPOSTWNDS; ih++) {
              if(&(PostingDocs[ih]) == CommDoc) {
#ifndef MAC
                 hWndPostEdit = hWndPostEdits[ih];
#else
  /* mrr add here */
#endif
                 found = TRUE;
                 break;
              }
            }
            retcode = 0;
            sscanf(CommLineIn,"%d",&retcode);
            if(retcode == 441 || retcode == 440) {
               cptr = "Posting Failed";
               mbcode = MB_OK|MB_ICONEXCLAMATION;
               done = TRUE;
            } else if(retcode == 240) {
               cptr = "Article Posted OK";
               mbcode = MB_OK;
               done = TRUE;
            }
            if(done) {
               CommBusy = FALSE;
               CommState = ST_NONE;
               MessageBox(hWndPostEdit,CommLineIn+4,cptr,mbcode);
            }
            break;

         case ST_MAIL_WAIT_PERMISSION:
            for(ih=0,found=FALSE; !found && ih<MAXMAILWNDS; ih++) {
              if(&(MailDocs[ih]) == CommDoc) {
#ifndef MAC
                 hWndPostEdit = hWndMailEdits[ih];
#else
  /* mrr add here */
#endif
                 found = TRUE;
                 break;
              }
            }
            retcode = 0;
            sscanf(CommLineIn,"%d",&retcode);
            if(retcode <= 0) {
               break;
            } else if(retcode == 350) {
               PostText(ih,DOCTYPE_MAIL);
            } else {
               MessageBox(hWndPostEdit,CommLineIn+4,"Cannot Mail Message",
                  MB_OK|MB_ICONEXCLAMATION);
               CommBusy = FALSE;
               CommState = ST_NONE;
            }

            break;

         case ST_MAIL_WAIT_END:
            for(ih=0,found=FALSE; !found && ih<MAXMAILWNDS; ih++) {
              if(&(MailDocs[ih]) == CommDoc) {
#ifndef MAC
                 hWndPostEdit = hWndMailEdits[ih];
#else
  /* mrr add here */
#endif
                 found = TRUE;
                 break;
              }
            }
            retcode = 0;
            sscanf(CommLineIn,"%d",&retcode);
            if(retcode == 451 || retcode == 450) {
               cptr = "Mailing Failed";
               mbcode = MB_OK|MB_ICONEXCLAMATION;
               done = TRUE;
            } else if(retcode == 250) {
               cptr = "Message sent OK";
               mbcode = MB_OK;
               done = TRUE;
            }
            if(done) {
               CommBusy = FALSE;
               CommState = ST_NONE;
               MessageBox(hWndPostEdit,CommLineIn+4,cptr,mbcode);
            }
            break;

      case ST_GROUP_REJOIN:
         CommState = ST_ARTICLE_RESP;
         break;
      }
   }
}

/*-- function WasArtSeen ---------------------------------------------
 *
 *  Determines whether (according to the information in a TypGroup entry)
 *  a given article number was seen.
 *
 *  Returns TRUE iff the article has been seen.
 */
BOOL
WasArtSeen(ArtNum,GroupPtr)
long int ArtNum;
TypGroup far *GroupPtr;
{
   TypRange far *RangePtr = (TypRange far *) ((char far *)
      GroupPtr + RangeOffset(GroupPtr->NameLen));
   int nr;

   for(nr=0; nr < GroupPtr->nRanges; nr++) {
      if(ArtNum >= RangePtr->First && ArtNum <= RangePtr->Last) {
         return(TRUE);
      } else {
         RangePtr++;
      }
   }
   return(FALSE);
}


/*--- function mylstrncmp -----------------------------------------------
 *
 *   Just like strncmp, except takes long pointers.
 */
int
mylstrncmp(ptr1,ptr2,len)
char far *ptr1;
char far *ptr2;
int len;
{
   for(;len--;ptr1++,ptr2++) {
      if(*ptr1 > *ptr2) {
         return(1);
      } else if(*ptr1 < *ptr2) {
         return(-1);
      }
   }
   return(0);
}

/*--- function mylstrncpy -----------------------------------------------
 *
 *   Just like strncpy, except takes long pointers.
 */
char far *
mylstrncpy(ptr1,ptr2,len)
char far *ptr1;
char far *ptr2;
int len;
{
   char far *targ = ptr1;

   for(; --len && *ptr2; ptr1++,ptr2++) {
      *ptr1 = *ptr2;
   }
   *ptr1 = '\0';
   return(targ);
}

/* this is a temporary test... */
char *
mylstrcpy (ptr1, ptr2)
char *ptr1;
char *ptr2;
{
  char far *targ = ptr1;
  for (; *ptr2; ptr1++, ptr2++) {
     *ptr1 = *ptr2;
  }
  *ptr1 = '\0';
  return (targ);
}

#if 0
/*--- function lstrcmpnoblank ------------------------------------------
 *
 *   Like strcmp, except takes long pointers and also stops at
 *   the first blank.
 */
int
lstrcmpnoblank(str1,str2)
char far **str1;
char far **str2;
{
   register char far *s1=*str1, far *s2=*str2;

	for(;*s1 && *s2 && *s1!=' ' && *s2!=' '; s1++,s2++) {
		if(*s1 > *s2) {
			return (1);
		} else if(*s1 < *s2) {
			return (-1);
		}
	}
	if(*s1 == *s2) {
		return(0);
	} else if(*s1) {
		return(1);
	} else {
		return(-1);
	}
}
#endif
