/*-- WVUTIL.C -- File containing utility routines. */ #include "windows.h" #include "wvglob.h" #include "winvn.h" #ifndef MAC #include "winundoc.h" #include #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 && ihNameLen)); 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