/* --- WVHEADER.C --------------------------------------------- * * This file contains the code necessary to create the initial skeleton * version of an article, which will be edited by the user. * * Mark Riordan 24-JAN-1990 */ #include "windows.h" #include "wvglob.h" #include "winvn.h" #ifndef MAC #include "winundoc.h" #include #include #endif #define MAXHEADERLINE 256 BOOL (*PostHeaderFuncs[])(TypDoc * Doc, char *Buf, long int BufLen) = { MakeArtHeaderFrom, MakeArtHeaderNewsgroups, MakeArtHeaderSubject, /* MakeArtHeaderMessageID, */ /* MakeArtHeaderDate, */ MakeArtHeaderReferences, MakeArtHeaderOrganization, /* MakeArtHeaderNewsreader, */ NULL }; BOOL (*MailHeaderFuncs[])(TypDoc * Doc, char *Buf, long int BufLen) = { MakeArtHeaderTo, MakeArtHeaderFrom, MakeArtHeaderSubject, MakeArtHeaderOrganization, NULL }; /*--- function GetHeaderLine ------------------------------------------- * * Given a document, get a line from the header portion of that document * whose prefix matches a given prefix. Prefix = first word in line. * For instance, you might call this routine to say "Get the 'Subject:'" * line from this document. * * Entry Doc points to the document whose header we are scanning. * The header is all the lines up to the first blank line. * Prefix is the character string which will identify the * line we are seeking. It is the first word * (blank-delimited) in a line in the header. * BufLen is the number of bytes left in the buffer Buf. * * Exit Returns TRUE iff we returned a line. * Buf if line was returned, contains that line, zero- * terminated. */ BOOL GetHeaderLine (Doc, Prefix, Buf, BufLen) TypDoc *Doc; char *Prefix; char *Buf; int BufLen; { char *bufptr = Buf; TypBlock far *BlockPtr; TypLine far *LinePtr; unsigned int Offset; HANDLE hBlock; TypLineID MyLineID; int found = FALSE; TopOfDoc (Doc, &BlockPtr, &LinePtr); while (ExtractTextLine (Doc, LinePtr, Buf, BufLen)) { /* Is this a blank line signifying the end of the header? */ if (IsLineBlank (Buf)) break; if (CompareStringNoCase (Buf, Prefix, strlen (Prefix)) == 0) { found = TRUE; break; } if (!NextLine (&BlockPtr, &LinePtr)) break; } UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID); return (found); } /*--- function CreatePostingWnd ----------------------------------------- * * Create the window for composing the text of a posting, * if it's OK to post. * * Entry Doc points to the document to which we are posting * a followup--NULL if it's a new posting. * * Exit Returns the handle of the newly-created window * (zero if failure). */ HWND CreatePostingWnd (Doc, DocType) TypDoc *Doc; int DocType; { int ih; BOOL found = FALSE; HWND hWnd = 0; int width, AveCharWidth; HDC hDC; #ifndef MAC TEXTMETRIC tmFontInfo; #endif char *TitlePtr, *WndName; if (DocType == DOCTYPE_POSTING) { WndName = "WinVnPost"; PostDoc = Doc; if (Doc) { TitlePtr = "Composing Followup Article"; } else { TitlePtr = "Composing New Article"; } for (ih = 0; !found && ih < MAXPOSTWNDS; ih++) { if (!hWndPosts[ih]) { found = TRUE; break; } } } else { WndName = "WinVnMail"; MailDoc = Doc; if (Doc) { TitlePtr = "Composing Reply Message"; } else { TitlePtr = "Composing New Mail Message"; } for (ih = 0; !found && ih < MAXMAILWNDS; ih++) { if (!hWndMails[ih]) { found = TRUE; break; } } } if (found && AuthenticatePosting ()) { #ifndef MAC hDC = GetDC (hWndConf); GetTextMetrics (hDC, (LPTEXTMETRIC) & tmFontInfo); AveCharWidth = tmFontInfo.tmAveCharWidth; ReleaseDC (hWndConf, hDC); if (xScreen > 78 * AveCharWidth) { width = 78 * AveCharWidth; } else { width = xScreen - 2 * AveCharWidth; } #else width = xScreen - 20; #endif hWnd = CreateWindow (WndName, TitlePtr, WS_OVERLAPPEDWINDOW /* | WS_VSCROLL */ , ih * CharWidth, /* Initial X pos */ (int) (yScreen * 3 / 8) + (1 + ih) * LineHeight, /* Initial Y pos */ (int) width, /* Initial X Width */ (int) (yScreen * 5 / 8) - (2 * LineHeight), /* Initial Y height */ NULL, NULL, hInst, NULL); if (hWnd) { #ifndef MAC ShowWindow (hWnd, SW_SHOWNORMAL); #else MyShowWindow (hWnd, SW_SHOWNORMAL); #endif UpdateWindow (hWnd); } } return (hWnd); } /*--- function CreatePostingText ------------------------------------------ * * Create the text of the skeleton article to be edited by * the user before posting. Display that text in an edit window. */ BOOL CreatePostingText (Doc, hWndPost, hWndEdit, DocType) TypDoc *Doc; HWND hWndPost; HWND hWndEdit; int DocType; { long int BytesLeft; char far *lpTextBuffer; char far *lpCurPtr; HANDLE hTextBuffer; BOOL gotline; char line[MAXHEADERLINE]; int ifunc; int nLines; long lParam; int RefCount; BOOL found; BOOL (**HeaderFuncs) (TypDoc * Doc, char *Buf, long int BufLen); #ifdef MAC long int textLength; TEHandle TEH; int ih; Rect viewRect, destRect; #endif if (DocType == DOCTYPE_POSTING) { HeaderFuncs = PostHeaderFuncs; } else { HeaderFuncs = MailHeaderFuncs; } /* Compute the number of bytes we need to hold a straight ASCII representation * of the initial text of the reply, and allocate a buffer of that size. */ found = 0; if (Doc) { BytesLeft = (2 + NumBlocksInDoc (Doc)) * Doc->BlockSize; } else { BytesLeft = 3000; } if (NULL == (hTextBuffer = GlobalAlloc (GHND, (DWORD) BytesLeft))) { MessageBox (hWndPost, "Cannot allocate memory for text", "", MB_OK); return FALSE; } lpCurPtr = lpTextBuffer = GlobalLock (hTextBuffer); for (ifunc = 0; HeaderFuncs[ifunc]; ifunc++) { gotline = (HeaderFuncs[ifunc]) (Doc, line, (long int) MAXHEADERLINE); if (gotline) { AppendTextToEditBuf (line, &lpCurPtr, &BytesLeft); } } MakeArtBody (Doc, &lpCurPtr, &BytesLeft, DocType); /* Set the edit window text to this skeleton article. */ #ifndef MAC SetWindowText (hWndEdit, lpTextBuffer); #else viewRect = hWndPost->portRect; viewRect.right -= SBarWidth; viewRect.bottom -= SBarWidth; destRect = viewRect; destRect.left = 3; SetPort (hWndPost); TEH = TENew (&destRect, &viewRect); TEHCurrent = TEH; (*TEH)->crOnly = -1; textLength = lstrlen (lpTextBuffer); TESetText (lpTextBuffer, textLength, TEH); SetView (hWndPost); ShowSelect (hWndPost); TEUpdate (&destRect, TEH); for (ih = 0, found = FALSE; !found && ih < MAXPOSTWNDS; ih++) { if (hWndPosts[ih] == hWndPost) { TEHPosts[ih] = TEH; found = TRUE; break; } } /* mrr add here */ #endif GlobalUnlock (hTextBuffer); GlobalFree (hTextBuffer); #if 0 strcpy (mesbuf, "Winc - Viewing "); strncat (mesbuf, NewMemos[imemo], MAXMEMONAME); SetWindowText (hWnd, mesbuf); #endif #ifndef MAC nLines = (int) SendMessage (hWndEdit, EM_GETLINECOUNT, 0, 0L); lParam = (long) ((long) nLines); /* while(nLines--) SendMessage(hWndEdit,WM_KEYDOWN,VK_DOWN,0L); */ #endif return TRUE; } /*--- functions MakeArtHeaderXXXXX --------------------------------------- * * Functions with names of the form MakeArtHeaderXxxxxx are all called * the same way and have similar purposes. They are called to * create and return a line of text that will become a line in * the header of an article to be posted. The source of * this information varies; it may be taken from an article * being replied to, it may be taken from a configuration file, * read from the system clock, etc. * * Entry Doc points to a document containing an article * being replied to; NULL if we're not replying * to an article. * BufLen is the length of the output buffer. * * Exit Returns TRUE iff we returned a line. * Buf contains the line, if any, terminated by a * zero byte. */ /*--- function MakeArtHeaderSubject ------------------------------------- * * Returned "Subject:" line is blank if no previous Subject: line * could be found. Otherwise, it is "Subject: Re: ". * If the article being replied to had a subject already starting * with "Re:", the "Re:" is not repeated. */ BOOL MakeArtHeaderSubject (Doc, Buf, BufLen) TypDoc *Doc; char *Buf; long int BufLen; { char HeadLine[MAXHEADERLINE]; BOOL gotline; char *outptr = Buf; char *headptr = HeadLine; CopyBuf ("Subject: ", &outptr, &BufLen); if (Doc) { gotline = GetHeaderLine (Doc, "Subject:", HeadLine, MAXHEADERLINE); if (gotline) { NextToken (&headptr); if (CompareStringNoCase (headptr, "Re:", 3) != 0) { CopyBuf ("Re: ", &outptr, &BufLen); } CopyBuf (headptr, &outptr, &BufLen); } else { DialogBox (hInst, "WinVnSubject", Doc->hDocWnd, lpfnWinVnSubjectDlg); CopyBuf (SubjectString, &outptr, &BufLen); } } else { DialogBox (hInst, "WinVnSubject", hWndConf, lpfnWinVnSubjectDlg); CopyBuf (SubjectString, &outptr, &BufLen); } return (TRUE); } #if 0 /*--- function MakeArtHeaderMessageID ---------------------------------- * * Returned "Message-ID:" line is computed from the time and * the ServerName (from Windows profile file). This needs to * be improved. */ BOOL MakeArtHeaderMessageID (Doc, Buf, BufLen) TypDoc *Doc; char *Buf; long int BufLen; { #define MAXSERVERNAME 32 char ServerName[MAXSERVERNAME]; GetPrivateProfileString (szAppName, "ServerName", "titan.ksc.nasa.gov", ServerName, MAXSERVERNAME, szAppProFile); sprintf (Buf, "Message-ID: <%ld@%s>", time ((time_t *) NULL), ServerName); return TRUE; } #endif /*--- function MakeArtHeaderFrom ---------------------------------- * * Returned "From:" is taken from Windows profile entries. */ BOOL MakeArtHeaderFrom (Doc, Buf, BufLen) TypDoc *Doc; char *Buf; long int BufLen; { char *outptr = Buf; CopyBuf ("From: ", &outptr, &BufLen); if (MailAddress[0]) { CopyBuf (MailAddress, &outptr, &BufLen); } else { CopyBuf ("", &outptr, &BufLen); } if (UserName[0]) { CopyBuf (" (", &outptr, &BufLen); CopyBuf (UserName, &outptr, &BufLen); CopyBuf (")", &outptr, &BufLen); } return TRUE; } /*--- function MakeArtHeaderTo ---------------------------------- * * Simply returns a blank "To:" line. */ BOOL MakeArtHeaderTo (Doc, Buf, BufLen) TypDoc *Doc; char *Buf; long int BufLen; { char HeadLine[MAXHEADERLINE]; char *outptr = Buf, *cptr = HeadLine; BOOL gotwho; CopyBuf ("To: ", &outptr, &BufLen); if (Doc) { gotwho = GetHeaderLine (Doc, "Reply-To:", HeadLine, MAXHEADERLINE); if (!gotwho) { gotwho = GetHeaderLine (Doc, "From:", HeadLine, MAXHEADERLINE); } if (gotwho) { NextToken (&cptr); while (*cptr && *cptr != ' ') { *(outptr++) = *(cptr++); } *outptr = '\0'; } } return TRUE; } /*--- function MakeArtHeaderOrganization ---------------------------------- * * Returned "Organization:" line is gotten from the Windows * profile file. */ BOOL MakeArtHeaderOrganization (Doc, Buf, BufLen) TypDoc *Doc; char *Buf; long int BufLen; { char *outptr = Buf; if (Organization[0]) { CopyBuf ("Organization: ", &outptr, &BufLen); CopyBuf (Organization, &outptr, &BufLen); return (TRUE); } return FALSE; } /*--- function MakeArtHeaderNewsreader ---------------------------------- * * Returned "Newsreader: " line is simply a constant. */ BOOL MakeArtHeaderNewsreader (Doc, Buf, BufLen) TypDoc *Doc; char *Buf; long int BufLen; { char *outptr = Buf; CopyBuf ("Newsreader: ", &outptr, &BufLen); CopyBuf ("MS Windows ", &outptr, &BufLen); CopyBuf (szAppName, &outptr, &BufLen); /* easier than examining this closely */ CopyBuf ("\r", &outptr , &BufLen); return (TRUE); } #if 0 /*--- function MakeArtHeaderDate ---------------------------------- * * Returned "Date:" line is computed from operating system time. * Be sure to set the TZ environment variable correctly for * "grtime" to work properly. Typical setting: SET TZ=EST5 */ BOOL MakeArtHeaderDate (Doc, Buf, BufLen) TypDoc *Doc; char *Buf; long int BufLen; { struct tm *timeptr; time_t curtime; curtime = time ((time_t *) NULL); timeptr = gmtime (&curtime); sprintf (Buf, "Date: %.4d-%.2d-%.2d %.2d:%.2d GMT", timeptr->tm_year + 1900, timeptr->tm_mon + 1, timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min); return TRUE; } #endif /*--- function MakeArtHeaderReferences ----------------------------------- * * Returned "References:" line contains all the previous article's * References (if any), plus its Message-ID (if any). */ BOOL MakeArtHeaderReferences (Doc, Buf, BufLen) TypDoc *Doc; char *Buf; long int BufLen; { char HeadLine[MAXHEADERLINE]; BOOL gotrefs; BOOL gotmesID; char *outptr = Buf; char *headptr = HeadLine; if (Doc) { gotrefs = GetHeaderLine (Doc, "References:", HeadLine, MAXHEADERLINE); if (gotrefs) { CopyBuf (HeadLine, &outptr, &BufLen); CopyBuf (" ", &outptr, &BufLen); } gotmesID = GetHeaderLine (Doc, "Message-ID:", HeadLine, MAXHEADERLINE); if (gotmesID) { if (!gotrefs) { CopyBuf ("References: ", &outptr, &BufLen); } NextToken (&headptr); CopyBuf (headptr, &outptr, &BufLen); } if (gotrefs || gotmesID) return (TRUE); } return FALSE; } /*--- function MakeArtHeaderNewsgroups ----------------------------------- * * Returned "Newsgroups:" line is simply a copy of previous article's. */ BOOL MakeArtHeaderNewsgroups (Doc, Buf, BufLen) TypDoc *Doc; char *Buf; long int BufLen; { char HeadLine[MAXHEADERLINE]; BOOL gotnews = FALSE; char *outptr = Buf; if (Doc) { gotnews = GetHeaderLine (Doc, "Newsgroups:", HeadLine, MAXHEADERLINE); if (gotnews) { CopyBuf (HeadLine, &outptr, &BufLen); } } if (!gotnews) { CopyBuf ("Newsgroups: ", &outptr, &BufLen); CopyBuf (NewsgroupsPtr, &outptr, &BufLen); } return TRUE; } /*--- function MakeArtBody ---------------------------------------------- * * Make the body of the article. This is null if there's no article * to reply to, else it's text of the form: * In article , says: * >line 1 * >line 2 * > ..... * * Entry Doc points to the article being replied to, else * NULL if none. * left is the number of bytes left in MesBuf. * * Exit MesBuf contains the added lines, and has been updated * to point to just after the last added byte. * left has been decremented appropriately. * Return value is not used, for now. */ BOOL MakeArtBody (Doc, MesBuf, left, DocType) TypDoc *Doc; char far **MesBuf; long int *left; int DocType; { HANDLE hBlock; unsigned int Offset; TypLineID MyLineID; TypBlock far *BlockPtr; TypLine far *LinePtr; char mesID[MAXHEADERLINE]; char from[MAXHEADERLINE]; char line[MAXHEADERLINE]; BOOL gotmesID, gotfrom; char *outptr = line; char *fromptr = from; char *mesptr = mesID; AppendTextToEditBuf ("", MesBuf, left); /* blank line after header */ /* Create the "In message xxx, yyy says:" line. */ if (Doc) { gotmesID = GetHeaderLine (Doc, "Message-ID:", mesID, MAXHEADERLINE); if (gotmesID) { NextToken (&mesptr); } else { mesptr = ""; } if (DocType == DOCTYPE_POSTING) { gotfrom = GetHeaderLine (Doc, "From:", from, MAXHEADERLINE); if (gotfrom) { NextToken (&fromptr); } else { fromptr = ""; } sprintf (line, "In article %s, %s says:", mesptr, fromptr); } else { sprintf (line, "In article %s, you say:", mesptr); } AppendTextToEditBuf (line, MesBuf, left); /* Skip past header of reply document. */ TopOfDoc (Doc, &BlockPtr, &LinePtr); while (ExtractTextLine (Doc, LinePtr, line, MAXHEADERLINE) && !IsLineBlank (line)) { if (!NextLine (&BlockPtr, &LinePtr)) break; } /* Copy body of reply document into the body of this article, */ /* prepending a ">" to each line. */ line[0] = '>'; while (ExtractTextLine (Doc, LinePtr, line + 1, MAXHEADERLINE - 1)) { AppendTextToEditBuf (line, MesBuf, left); if (!NextLine (&BlockPtr, &LinePtr)) break; } UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID); } return TRUE; } /*--- function CompareStringNoCase ------------------------------------- * * Compare two strings, case insensitive. * * Entry str1, str2 are two strings to compare. * slen is the number of characters to compare * (but stop at a zero byte). * * Exit returns -1 if str1 is earlier in collating sequence, * 0 if strings are equal, 1 otherwise */ int CompareStringNoCase (str1, str2, slen) char *str1; char *str2; int slen; { while (slen-- && *str1 && *str2) { if (_tolower (*str1) < _tolower (*str2)) { return (-1); } else if (_tolower (*str1) > _tolower (*str2)) { return (1); } str1++; str2++; } return (0); } /*--- function CopyBuf ----------------------------------------------- * * Copy a string into a buffer, being sure not to overrun the * buffer. * * Entry instr points to the string to copy into the buffer, * zero-terminated. * buf is the buffer * left is the number of bytes left in the buffer * Exit buf contains the LWA+1 of the bytes copied into * the output buffer. A Zero byte is stored * into this location. * left is the number of bytes left in the buffer. */ void CopyBuf (instr, buf, left) char *instr; char **buf; long int *left; { while (--(*left) > 1 && *instr) { *((*buf)++) = *(instr++); } if (*left > 0) **buf = '\0'; } /*--- function NextToken ----------------------------------------------- * * Position a pointer to the next token in a string. * Delimiters are space and tab. * * Entry cptr points to a position in a zero-terminated string. * * Exit Returns TRUE iff a next token was found. * cptr points to the next token, if found--else * it is unchanged. */ BOOL NextToken (cptr) char **cptr; { /* Skip to end of current token, if any. */ while (**cptr != ' ' && **cptr != '\t' && **cptr) (*cptr)++; /* Skip past white space. */ while (**cptr && (**cptr == ' ' || **cptr == '\t')) (*cptr)++; if (**cptr) { return (TRUE); } else { return (FALSE); } } /*--- function AppendTextToEditBuf ---------------------------------------- * * Appends a zero-terminated text line to a buffer to be given * to an Edit window. Used in building messages to be displayed * and edited by an Edit window. * * Entry instr points to a text line to add. It is terminated * by a zero byte and does not end in CR or LF. * left is the number of characters left in buf. * * Exit buf contains the line, terminated by CR and LF. * buf now points to the next available byte. * left has been decremented as appropriate. */ void AppendTextToEditBuf (instr, buf, left) char *instr; char far **buf; long int *left; { while (--(*left) > 0 && *instr) { *((*buf)++) = *(instr++); } if (--(*left) > 0) *((*buf)++) = '\r'; #ifndef MAC if (--(*left) > 0) *((*buf)++) = '\n'; #endif if ((*left) > 0) **buf = '\0'; } /*--- function IsLineBlank ------------------------------------------------ * * Determine whether a zero-terminated line is blank. * "Blank" means it contains nothing but spaces and tabs. * * Entry line points to the line. * * Exit returns TRUE iff the line is blank. */ BOOL IsLineBlank (line) char far *line; { while (*line == ' ' || *line == '\t' || *line == '\n') line++; return (!(*line)); }