home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Otherware
/
Otherware_1_SB_Development.iso
/
mac
/
util
/
comm
/
news102.sit
/
NewsWatcher
/
source
/
newsprocess.c
< prev
next >
Wrap
Text File
|
1991-04-03
|
46KB
|
1,929 lines
/*----------------------------------------------------------
#
# NewsWatcher - Macintosh NNTP Client Application
#
# Written by Steven Falkenburg
# ⌐1990 Apple Computer, Inc.
#
#-----------------------------------------------------------
#
# newsprocess.c
#
# This code module contains miscellaneous routines
# called by many of the other code segments.
# The memory management routines and status window
# routines are contained in this module.
#
#-----------------------------------------------------------*/
#pragma segment newsprocess
#include "compat.h"
#ifdef PROTOS
#include <Types.h>
#include <QuickDraw.h>
#include <Fonts.h>
#include <Windows.h>
#include <Menus.h>
#include <TextEdit.h>
#include <Dialogs.h>
#include <OSUtils.h>
#include <Desk.h>
#include <ToolUtils.h>
#include <OSEvents.h>
#include <Lists.h>
#include <CursorCtl.h>
#include <Packages.h>
#include <Errors.h>
#include <CType.h>
#include <Strings.h>
#endif
#include <StdIO.h>
#include <String.h>
#include "nntp.h"
#include "newsprocess.h"
#include "userint.h"
#include "commands.h"
#include "miscstuff.h"
#include "netstuff.h"
#ifdef NNTPNEWS
#include "NNTPLow.h"
#else
#include "HFSNTPLow.h"
#endif
/* InitSubjectList is called to set up an empty subject list
data structure. The subjects are stored in a handle, which
is dynamically grown and locked.
*/
void InitSubjectList(TwindowInfo *theInfo)
{
theInfo->data2 = (unsigned long)MyNewHandle(1);
HLock((Handle)theInfo->data2);
theInfo->numSubjects = 0;
}
/* AddToSubjectList gets a range of messages from the NNTP server and puts
them in the subject list. The data structure is grown accordingly.
*/
void AddToSubjectList(TwindowInfo *theInfo,char *newsGroup,long first,long last)
{
ListHandle theList;
long i,numMessages;
Cell theCell,oldCell;
TSubject *theSubjects;
Str255 tmpStr;
extern TPrefRec gPrefs;
theList = (ListHandle) theInfo->data;
/* get max specified msgs */
if (last-first > gPrefs.maxFetch)
first = last-gPrefs.maxFetch;
HUnlock((Handle)theInfo->data2);
MySetHandleSize((Handle)theInfo->data2,GetHandleSize((Handle)theInfo->data2)+(sizeof(TSubject)*(last-first+1)));
if (MyMemErr() != noErr) {
MoveHHi((Handle)theInfo->data2);
HLock((Handle)theInfo->data2);
return;
}
MoveHHi((Handle)theInfo->data2);
HLock((Handle)theInfo->data2);
theSubjects = (TSubject *) *((Handle)theInfo->data2);
LDoDraw(false,theList);
if (GetMessages(newsGroup,first,last,&theSubjects[theInfo->numSubjects],&numMessages,"SUBJECT") == noErr) {
StatusWindow("Building Subject List...",-1);
GiveTime(0);
for (i=theInfo->numSubjects; i<numMessages+theInfo->numSubjects; i++) {
SetPt(&theCell,0,0);
oldCell = theCell;
strcpy((char *)tmpStr,theSubjects[i].name);
tmpStr[strlen((char *)tmpStr)+1] = 0xff;
DisposPtr(theSubjects[i].name);
if (!gPrefs.mostRecentFirst) {
while (LSearch(tmpStr,strlen((char *)tmpStr)+2,SubjectCompare,&theCell,theList)) {
theCell.v++;
oldCell = theCell;
GiveTime(0);
}
if (oldCell.v != 0)
theCell = oldCell;
}
else
if (!LSearch(tmpStr,strlen((char *)tmpStr)+2,SubjectCompare,&theCell,theList))
theCell.v = 0;
LAddRow(1,theCell.v,theList);
LSetCell(tmpStr,strlen((char *)tmpStr)+2,theCell,theList);
StatusWindow("Building Subject List...",(short)(((float)(i+1)/(float)(numMessages+theInfo->numSubjects))*100));
GiveTime(0);
}
}
LDoDraw(true,theList);
theInfo->numSubjects += numMessages;
SetCursor(&QDARROW);
}
/* SubjectCompare is used to determine where to insert a new subject string
into an existing list of subjects. The Re: and article number are stripped,
and the subject strings are then compared.
*/
pascal short SubjectCompare(char *aPtr,char *bPtr,short aLen,short bLen)
{
/* remove leading space */
aPtr++;
bPtr++;
aLen--;
bLen--;
/* remove article numbers */
while (aPtr && *aPtr != ' ') {
aPtr++;
aLen--;
}
while (bPtr && *bPtr != ' ') {
bPtr++;
bLen--;
}
/* remove reply indicator */
if (strncmp(aPtr," Re:",4)==0) {
aPtr += 4;
aLen -= 4;
}
if (strncmp(bPtr," Re:",4)==0) {
bPtr += 4;
bLen -= 4;
}
return IUMagIDString(aPtr,bPtr,aLen,bLen);
}
/* This routine removes colons, check marks, or returns from the titles of
articles. This insures that the string returned is a legal filename.
*/
char *TitleFilter(char *title)
{
short i;
for (i=1; i<=title[0]; i++) {
switch (title[i]) {
case CR:
case ':':
case '├':
title[i] = ' ';
break;
}
}
if (title[0] > 31)
title[0] = 31;
return title;
}
/* DoSaveWindow is called when the user issues a Save command for a
NEW article window. The text of the article is saved to a text file
on disk.
*/
Boolean DoSaveWindow(WindowPtr wind)
{
Point where = {100,100};
SFReply reply;
Str255 defaultName;
TwindowInfo *info;
OSErr err;
long count;
short fRefNum;
GetWTitle(wind,defaultName);
TitleFilter((char *)defaultName);
info = (TwindowInfo *)GetWRefCon(wind);
SFPutFile(where,(StringPtr)"\pSave message as:",defaultName,nil,&reply);
if (!reply.good)
return false;
if ((err = Create(reply.fName,reply.vRefNum,kTextCreator,'TEXT')) == dupFNErr) {
FSOpen(reply.fName,reply.vRefNum,&fRefNum);
err = SetEOF(fRefNum,0);
FSClose(fRefNum);
}
if (err != noErr)
return false;
if (FSOpen(reply.fName,reply.vRefNum,&fRefNum) != noErr)
return false;
HLock((**(TEHandle)info->data).hText);
count = (**(TEHandle)info->data).teLength;
FSWrite(fRefNum,&count,*(**(TEHandle)info->data).hText);
FSClose(fRefNum);
HUnlock((**(TEHandle)info->data).hText);
return true;
}
/* DoSaveMessage is called when the user wishes to save the text
of an article which was fetched from the network. In this case,
the full text of the article must be fetched before the save, since
we must allow >32k messages.
*/
Boolean DoSaveMessage(TwindowInfo *info)
{
Point where = {100,100};
SFReply reply;
Str255 defaultName;
char *text;
long length;
long offset,offset2,offset3;
Handle teText;
char messageID[256];
OSErr err;
short fRefNum;
char mungeText[256];
if (!FrontWindow()) {
SysBeep(1);
return false;
}
GetWTitle(FrontWindow(),defaultName);
teText = (Handle) TEGetText((TEHandle)info->data);
offset = Munger(teText,0L,"Message-ID:",11L,nil,0L);
offset2 = Munger(teText,offset,CRSTR,1L,nil,0L);
strcpy(mungeText,CRSTR);
strcat(mungeText,CRSTR);
offset3 = Munger(teText,0L,mungeText,2L,nil,0L);
if (offset < 0 || offset2 < 0 || offset3 < 0 || offset2 > offset3)
return false;
offset += 11;
HLock(teText);
strncpy(messageID,(*teText)+offset,offset2 - offset);
messageID[offset2-offset] = '\0';
HUnlock(teText);
if (GetArticle(nil,messageID,&text,&length,kMaxSaveLength) != noErr)
return false;
TitleFilter((char *)defaultName);
SFPutFile(where,(StringPtr)"\pSave message as:",defaultName,nil,&reply);
if (!reply.good)
return false;
if ((err = Create(reply.fName,reply.vRefNum,kTextCreator,'TEXT')) == dupFNErr) {
FSOpen(reply.fName,reply.vRefNum,&fRefNum);
err = SetEOF(fRefNum,0);
FSClose(fRefNum);
}
if (err != noErr) {
MyDisposPtr(text);
return false;
}
if (FSOpen(reply.fName,reply.vRefNum,&fRefNum) != noErr) {
MyDisposPtr(text);
return false;
}
FSWrite(fRefNum,&length,text);
FSClose(fRefNum);
MyDisposPtr(text);
}
/* DoOpenFile is called when the user issues an Open Group List command
from the File menu. This will prompt for a groups list to open.
*/
void DoOpenFile(void)
{
Point where = {100,100};
SFReply reply;
SFGetFile(where,(StringPtr)"\p",nil,1,(OSType *)"NEWS",nil,&reply);
if (reply.good)
LoOpenFile(reply.fName,reply.vRefNum);
}
/* LoOpenFile is called by DoOpenFile once a name and vRefNum have been
entered by the user. This routine then opens the file and parses it
for groups.
*/
OSErr LoOpenFile(Str255 fName,short vRefNum)
{
OSErr err;
short fRefNum;
long length;
char *newsrc,*current;
WindowPtr window;
TwindowInfo *info;
Point thePt;
extern TPrefRec gPrefs;
if ((err = FSOpen(fName,vRefNum,&fRefNum)) != noErr)
return err;
if ((err = GetEOF(fRefNum,&length)) == noErr) {
newsrc = current = (char *)MyNewPtr(length+1);
if ((err = MyMemErr()) == noErr) {
if ((err = FSRead(fRefNum,&length,newsrc)) == noErr) {
newsrc[length] = '\0';
info = (TwindowInfo *)GetWRefCon(window = NewGroupWindow(fName));
BlockMove(fName,info->diskFile,fName[0]+1);
info->diskVRefNum = vRefNum;
LDoDraw(false,(ListHandle)info->data);
while (*current)
ProcessLine(¤t,window);
LDoDraw(true,(ListHandle)info->data);
SetPt(&thePt,0,0);
LSetSelect(true,thePt,(ListHandle)info->data);
info->changed = false;
info->saved = true;
if (gPrefs.openWindowsZoomed)
ToggleZoom(window);
ShowWindow(window);
SetPort(window);
InvalRect(&window->portRect);
}
MyDisposPtr(newsrc);
}
}
FSClose(fRefNum);
SetCursor(&QDARROW);
return err;
}
/* ProcessLine parses out a group name and group information for a single
line in the newsrc file. The group is then added to the new window.
*/
void ProcessLine(char **newsrc,WindowPtr window)
{
char newsGroup[256],*current;
extern short gNumGroups;
extern TGroup *gGroupList;
TGroup *newGroup;
long i,prev,totalLast,first,last;
Boolean done;
Cell theCell;
short nameLen;
for (current = newsGroup;
**newsrc && **newsrc != ':' && **newsrc != '!';
*current++ = *(*newsrc)++)
;
*current = '\0';
if (**newsrc == ':') {
(*newsrc)++;
for (i=0; i<gNumGroups && strcmp(newsGroup,gGroupList[i].name)!=0; i++)
;
if (i<gNumGroups && (newGroup = Subscribe(&gGroupList[i],window,&theCell))) {
prev = newGroup->read->firstRead;
totalLast = newGroup->read->lastRead;
MyDisposPtr((Ptr)newGroup->read);
newGroup->read = nil;
done = false;
do {
while (**newsrc && **newsrc != CR && **newsrc<'0' && **newsrc>'9')
(*newsrc)++;
if (**newsrc && **newsrc != CR) {
GetBlank(newsrc);
GetNumber(newsrc,&first);
GetBlank(newsrc);
if (**newsrc=='-') {
(*newsrc)++;
GetBlank(newsrc);
GetNumber(newsrc,&last);
}
else
last = first;
if (prev <= (first-1))
MarkRead(prev,first-1,newGroup);
prev = last+1;
}
else {
done = true;
if (totalLast >= last+1)
MarkRead(last+1,totalLast,newGroup);
}
} while (!done);
if (newGroup->read==nil) {
nameLen = 256;
LGetCell(newsGroup,&nameLen,theCell,(ListHandle)((TwindowInfo *)GetWRefCon(window))->data);
if ( ((unsigned char) newsGroup[nameLen-1]) != 0xff ) {
newsGroup[strlen(newsGroup)+1] = 0xff;
LSetCell(newsGroup,strlen(newsGroup)+2,theCell,(ListHandle)((TwindowInfo *)GetWRefCon(window))->data);
}
}
}
GiveTime(0);
}
while (**newsrc && **newsrc != CR)
(*newsrc)++;
if (**newsrc)
(*newsrc)++;
}
/* GetNumber parses a number out of a string, returing the number and moving the
string pointer past the position of the number.
*/
void GetNumber(char **newsrc,long *number)
{
char *current,numStr[256];
current = numStr;
while (**newsrc && **newsrc>='0' && **newsrc<='9')
*current++ = *(*newsrc)++;
*current = '\0';
StringToNum((StringPtr)c2pstr(numStr),number);
}
/* GetBlank eats blank characters from an input string.
*/
void GetBlank(char **newsrc)
{
while (**newsrc && **newsrc == ' ' || **newsrc == ',')
(*newsrc)++;
}
/* CheckForSave asks the user if he/she would like to save a group
list before the changes have been discarded.
*/
Boolean CheckForSave(WindowPtr wind)
{
TwindowInfo *info;
info = (TwindowInfo *)GetWRefCon(wind);
ParamText(info->diskFile,"\p","\p","\p");
SetCursor(&QDARROW);
switch (Alert(kCheckSaveID,CmdKeyFilter)) {
case kYes:
return (DoSaveFile(wind));
break;
case kNo:
return true;
break;
case kCancel:
return false;
break;
}
}
/* CheckForSend asks the user if he/she would like to send the message
that they composed before the window has been closed.
*/
Boolean CheckForSend(WindowPtr wind)
{
SetCursor(&QDARROW);
switch (Alert(kAskSendAlert,CmdKeyFilter)) {
case kYes:
return (DoSendMsg((TwindowInfo *)GetWRefCon(wind)));
break;
case kNo:
return true;
case kCancel:
return false;
}
}
/* DoSaveFile is called to save a group list to disk in newsrc format.
*/
Boolean DoSaveFile(WindowPtr wind)
{
TwindowInfo *info;
info = (TwindowInfo *)GetWRefCon(wind);
if (info->saved) {
info->changed = false;
return LoSaveFile(info->childList,(TGroup *)info->data2,info->diskFile,info->diskVRefNum);
}
else
return DoSaveAsFile(wind);
}
/* DoSaveAsFile is called when the group list to be saved has not been
written to disk before.
*/
Boolean DoSaveAsFile(WindowPtr wind)
{
Point where = {100,100};
SFReply reply;
TwindowInfo *info;
Boolean good;
info = (TwindowInfo *)GetWRefCon(wind);
SFPutFile(where,"\pSave group list as:",info->diskFile,nil,&reply);
if (!reply.good)
return false;
if (good = LoSaveFile(info->childList,(TGroup *)info->data2,reply.fName,reply.vRefNum)) {
RemoveWindowsMenu(wind);
SetWTitle(wind,reply.fName);
AddWindowsMenu(wind);
BlockMove(reply.fName,info->diskFile,reply.fName[0]+1);
info->diskVRefNum = reply.vRefNum;
info->changed = false;
info->saved = true;
}
return good;
}
/* LoSaveFile is the low-level routine which writes the groups out to the
group file on disk.
*/
Boolean LoSaveFile(TWList *children,TGroup *groups,Str255 fName,short vRefNum)
{
OSErr err;
short fRefNum;
long length,first;
TGroup *theGroup;
char tmpStr[256];
TReadRec *read;
TWList *current;
short offset;
/* update read lists */
for (current = children; current != nil; current = current->next)
MarkReadMsgs((TwindowInfo *) GetWRefCon(current->childWindow));
if ((err = Create(fName,vRefNum,kFCreator,kFType)) == dupFNErr) {
FSOpen(fName,vRefNum,&fRefNum);
err = SetEOF(fRefNum,0);
FSClose(fRefNum);
}
if (err != noErr)
return false;
if (FSOpen(fName,vRefNum,&fRefNum) != noErr)
return false;
for (theGroup = groups; theGroup!=nil; theGroup=theGroup->next) {
length = strlen(theGroup->name);
FSWrite(fRefNum,&length,theGroup->name);
length = 2;
FSWrite(fRefNum,&length,": ");
first = 1;
for (read = theGroup->read; read!=nil; read = read->next) {
if ( (read->firstRead-1 - first) >= 0) {
sprintf(tmpStr,"%lu-%lu",first,(read->firstRead-1));
if (read->next)
strcat(tmpStr,",");
length = strlen(tmpStr);
FSWrite(fRefNum,&length,tmpStr);
}
first = 1 + read->lastRead;
}
/* mark read to last message of group */
if (theGroup->lastMess >= first) {
sprintf(tmpStr,", %lu-%lu",first,theGroup->lastMess);
if (first==1)
offset=1;
else
offset=0;
length = strlen(tmpStr+offset);
FSWrite(fRefNum,&length,tmpStr+offset);
}
length = 1;
FSWrite(fRefNum,&length,CRSTR);
}
FSClose(fRefNum);
return true;
}
/* MarkReadMsgs is called to update the read messages list for a group.
Each subject in the list preceeded by a ├ (check mark) is marked as
read in the internal data structure.
*/
void MarkReadMsgs(TwindowInfo *theInfo)
{
long tmpFirst,tmpLast,i;
TReadRec *read,*tmp;
TGroup *theGroup;
TSubject *subjects;
TwindowInfo *parentInfo;
char groupName[256];
short nameLen;
Cell theCell;
theGroup = theInfo->parentGroup;
parentInfo = (TwindowInfo *)GetWRefCon(theInfo->parentWindow);
parentInfo->changed = true;
subjects = (TSubject *)*(Handle)theInfo->data2;
read = theGroup->read;
while (read != nil) {
tmp = read;
read = read->next;
MyDisposPtr((Ptr)tmp);
}
theGroup->read = nil;
tmpFirst = -1;
for (i=0; i<theInfo->numSubjects; i++) {
if (!subjects[i].read && i<(theInfo->numSubjects-1) && subjects[i+1].number-subjects[i].number > 1) {
if (tmpFirst == -1)
tmpFirst = subjects[i].number;
MarkRead(tmpFirst,subjects[i].number,theGroup);
tmpFirst = -1;
}
else if (tmpFirst == -1 && !subjects[i].read)
tmpFirst = tmpLast = subjects[i].number;
else if (tmpFirst != -1 && !subjects[i].read)
tmpLast = subjects[i].number;
else if (tmpFirst != -1 && subjects[i].read) {
MarkRead(tmpFirst,tmpLast,theGroup);
tmpFirst = -1;
}
}
if (tmpFirst != -1)
MarkRead(tmpFirst,tmpLast,theGroup);
if (theGroup->read==nil) {
SetPt(&theCell,0,0);
if (LSearch(theGroup->name,strlen(theGroup->name),CompareStart,&theCell,(ListHandle)parentInfo->data)) {
nameLen = 256;
LGetCell(groupName,&nameLen,theCell,(ListHandle)parentInfo->data);
if ( ((unsigned char) groupName[nameLen-1]) != 0xff ) {
groupName[strlen(groupName)+1] = 0xff;
LSetCell(groupName,strlen(groupName)+2,theCell,(ListHandle)parentInfo->data);
}
}
}
}
/* CompareStart is a string comparison routine which returns the strings as
equal if they share a common prefix. This routine also ignores leading spaces
and check marks.
*/
pascal short CompareStart(Ptr aPtr,Ptr bPtr,short aLen,short bLen)
{
while (*aPtr == ' ' || *aPtr == '├') {
aPtr++;
aLen--;
}
while (*bPtr == ' ' || *bPtr == '├') {
bPtr++;
bLen--;
}
if (aLen < bLen)
bLen = aLen;
else if (bLen < aLen);
aLen = bLen;
return IUMagIDString(aPtr,bPtr,aLen,bLen);
}
/* MarkRead marks a range of messages _unread_ in the internal database for
the specified group.
*/
void MarkRead(long first,long last,TGroup *theGroup)
{
TReadRec *read,*lastRec;
read = (TReadRec *)MyNewPtr(sizeof(TReadRec));
if (MyMemErr() != noErr)
return;
read->firstRead = first;
read->lastRead = last;
read->next = nil;
if (theGroup->read) {
for (lastRec = theGroup->read; lastRec->next; lastRec=lastRec->next)
;
lastRec->next = read;
}
else theGroup->read = read;
}
/* MarkXrefsRead marks articles which appear in multiple newsgroups as read
in both of those newsgroups.
*/
void MarkXrefsRead(TEHandle message,TGroup *groupList)
{
long offset,endHeader,endLine;
Handle theText;
char *current,*store;
char xrefGroup[256];
char xrefNumber[256];
long number;
char mungeText[256];
strcpy(mungeText,CRSTR);
strcat(mungeText,"Xref:");
theText = (Handle) TEGetText((TEHandle)message);
offset = Munger((Handle)theText,0L,mungeText,6L,nil,0L);
if (offset < 0) {
offset = Munger(theText,0L,"Xref:",5L,nil,0L);
if (offset != 0)
offset = -1;
}
if (offset < 0)
return;
strcpy(mungeText,CRSTR);
strcat(mungeText,CRSTR);
endHeader = Munger(theText,0L,mungeText,2L,nil,0L);
if (offset > endHeader)
return;
endLine = Munger(theText,offset,CRSTR,1L,nil,0L);
HLock(theText);
current = (*theText)+offset;
/* skip over site name */
current += 6;
while (*current == ' ' && *current != CR)
current++;
while (*current != ' ' && *current != CR)
current++;
/* parse xrefed groups */
while (current < (*theText)+endLine) {
store = xrefGroup;
while (*current == ' ' && *current != CR)
current++;
while (*current != ':' && *current != ' ' && *current != CR) {
*store++ = *current++;
}
current++;
*store = '\0';
store = xrefNumber;
while (*current != ' ' && *current != ' ' && *current != CR)
*store++ = *current++;
*store = '\0';
c2pstr(xrefNumber);
StringToNum(xrefNumber,&number);
MarkOneRead(xrefGroup,number,groupList);
}
HUnlock(theText);
}
/* MarkOneRead marks a single message in a specified group as being read.
*/
void MarkOneRead(char *groupName,long number,TGroup *groupList)
{
TGroup *theGroup;
TReadRec *read,*newRead,*prevRead;
for (theGroup = groupList;
theGroup && strcmp(theGroup->name,groupName)!=0;
theGroup = theGroup->next);
if (!theGroup)
return;
for (read = prevRead = theGroup->read;
read && !(number>=read->firstRead && number<=read->lastRead);
prevRead = read,read = read->next);
if (!read) /* already read */
return;
if (number == read->firstRead) {
read->firstRead++;
if (read->firstRead == read->lastRead) {
if (read != prevRead)
prevRead->next = read->next;
else
theGroup->read = read->next;
DisposPtr((Ptr)read);
}
return;
}
if (number == read->lastRead) {
read->lastRead--;
if (read->firstRead == read->lastRead) {
if (read != prevRead)
prevRead->next = read->next;
else
theGroup->read = read->next;
DisposPtr((Ptr)read);
}
return;
}
/* split this one in half */
newRead = (TReadRec *)NewPtr(sizeof(TReadRec));
newRead->next = read->next;
read->next = newRead;
newRead->lastRead = read->lastRead;
newRead->firstRead = number + 1;
read->lastRead = number - 1;
}
/* Subscribe adds the given group to the list of groups to which the
user is subscribed. This is called when a user drags a group from
the main group list into his/her user group list.
*/
TGroup *Subscribe(TGroup *theGroup,WindowPtr theWindow,Cell *retCell)
{
ListHandle theList;
Cell theCell;
TwindowInfo *theInfo;
TGroup *tmpPtr,*last;
short cellSize;
char tmpName[256];
theInfo = (TwindowInfo *)GetWRefCon(theWindow);
theInfo->changed = true;
for (tmpPtr = (TGroup *)theInfo->data2;
tmpPtr && strcmp(theGroup->name,tmpPtr->name)!=0;
tmpPtr = tmpPtr->next)
;
if (tmpPtr) {
SysBeep(1);
return nil;
}
/* I do this to keep order by inserting at the end of newsgroups */
tmpPtr = (TGroup *)MyNewPtr(sizeof(TGroup));
if (MyMemErr() != noErr)
return nil;
strcpy(tmpPtr->name,theGroup->name);
tmpPtr->firstMess = theGroup->firstMess;
tmpPtr->lastMess = theGroup->lastMess;
tmpPtr->status = theGroup->status;
tmpPtr->read = (TReadRec *)MyNewPtr(sizeof(TReadRec));
if (MyMemErr() != noErr)
return nil;
tmpPtr->read->firstRead = theGroup->firstMess;
tmpPtr->read->lastRead = theGroup->lastMess;
tmpPtr->read->next = nil;
strcpy(tmpName,tmpPtr->name);
if ( (tmpPtr->lastMess - tmpPtr->firstMess) <= 0 ) {
cellSize = strlen(tmpName)+2;
tmpName[strlen(tmpName)+1] = 0xff;
}
else
cellSize = strlen(tmpName)+1;
tmpPtr->next = nil;
for (last = (TGroup *) theInfo->data2;
last && last->next != nil;
last = last->next)
;
if (!last)
theInfo->data2 = (unsigned long) tmpPtr;
else
last->next = tmpPtr;
theList = (ListHandle)theInfo->data;
SetPt(&theCell,0,LAddRow(1,theInfo->numGroups++,theList));
LSetCell(tmpName,cellSize,theCell,theList);
LDraw(theCell,theList);
*retCell = theCell;
return tmpPtr;
}
/* DoMarkArticleRead is called when a user selects Mark Read from the
News menu. It marks all selected articles in window read.
*/
void DoMarkArticleRead(Boolean read)
{
TwindowInfo *info;
Cell theCell;
if (!IsAppWindow(FrontWindow()))
return;
info = (TwindowInfo *)GetWRefCon(FrontWindow());
if (info->kind != cSubject)
return;
theCell.h = theCell.v = 0;
while (LGetSelect(true,&theCell,(ListHandle)info->data)) {
LoMarkArticleRead(info,theCell,read);
theCell.v++;
}
}
/* LoMarkArticleRead is the low-level procedure which inserts check marks
into the subjects which are passed in at theCell.
*/
void LoMarkArticleRead(TwindowInfo *info,Cell theCell,Boolean read)
{
short nameLen;
char *tmpStr,*tmpStr2;
char numStr[256],title[256];
long number,i;
nameLen = 256;
LGetCell(title,&nameLen,theCell,(ListHandle)info->data);
for (tmpStr = numStr,tmpStr2 = title+1;
*tmpStr2 != ' ' && *tmpStr2 != '├' && *tmpStr2 != '\0';
*tmpStr++ = *tmpStr2++)
;
*tmpStr = '\0';
c2pstr(numStr);
StringToNum(numStr,&number);
if (info->parentGroup) {
*title = (read) ? '├' : ' ';
LSetCell(title,nameLen,theCell,(ListHandle)info->data);
for (i=0; i<info->numSubjects && ((TSubject *)*((Handle)info->data2))[i].number != number; i++)
;
if (i<=info->numSubjects)
((TSubject *)*((Handle)info->data2))[i].read = read;
else
SysBeep(1);
}
}
/* DoMarkGroupRead marks all selected groups in a group window read.
It is also called in response to a Mark Read command in the News
menu.
*/
void DoMarkGroupRead(Boolean read)
{
TwindowInfo *info;
Cell theCell;
short nameLen;
TWList *children;
Str255 wTitle;
char name[256];
Boolean matched;
unsigned char readChar;
readChar = (read) ? 0xff : 0x00;
if (!IsAppWindow(FrontWindow()))
return;
info = (TwindowInfo *)GetWRefCon(FrontWindow());
if (info->kind != cUserGroup)
return;
theCell.h = theCell.v = 0;
while (LGetSelect(true,&theCell,(ListHandle)info->data)) {
nameLen = 256;
LGetCell(name,&nameLen,theCell,(ListHandle)info->data);
for (matched=false,children=info->childList; children!=nil && !matched; children=children->next) {
GetWTitle(children->childWindow,wTitle);
p2cstr(wTitle);
matched = (strcmp((char *)wTitle,name) == 0);
}
if (!matched) {
if ( ((unsigned char) name[nameLen-1]) != readChar) {
name[strlen(name)+1] = readChar;
LSetCell(name,strlen(name)+2,theCell,(ListHandle)info->data);
}
LoMarkGroupRead(name,(TGroup *)info->data2,read);
}
else
SysBeep(1);
theCell.v++;
}
}
/* LoMarkGroupRead marks all articles in the selected group read.
*/
void LoMarkGroupRead(char groupName[256],TGroup *firstGroup,Boolean isRead)
{
TGroup *group;
TReadRec *read;
for (group = firstGroup;
group != nil && strcmp(group->name,groupName)!=0;
group = group->next)
;
while (group->read) {
read = group->read;
group->read = group->read->next;
MyDisposPtr((Ptr)read);
}
if (!isRead) {
read = (TReadRec *) MyNewPtr(sizeof(TReadRec));
read->firstRead = group->firstMess;
read->lastRead = group->lastMess;
read->next = group->read;
group->read = read;
}
}
/* SubscribeSelected subscribes the user to all selected newsgroups
by calling Subscribe() above.
*/
void SubscribeSelected(TwindowInfo *info,ListHandle srcList,WindowPtr destWindow)
{
Cell theCell,newCell;
TGroup *theGroup;
char groupName[256];
short nameLen;
SetPt(&theCell,0,0);
while (LGetSelect(true,&theCell,srcList)) {
nameLen = 256;
LGetCell(groupName,&nameLen,theCell,srcList);
if (FindGroup(info,groupName,&theGroup))
Subscribe(theGroup,destWindow,&newCell);
theCell.v++;
}
}
/* HandleSubscribe is called when the user selects the Subscribe command
from the News menu. It calls SubscribeSelected() above.
*/
void HandleSubscribe(void)
{
TwindowInfo *info;
WindowPtr destWindow;
Boolean done;
if (!FrontWindow()) {
SysBeep(1);
return;
}
info = (TwindowInfo *)GetWRefCon(FrontWindow());
if (info->kind != cGroup && info->kind != cNewGroup)
return;
for (done=false,destWindow = (WindowPtr) ((WindowPeek)FrontWindow())->nextWindow;
destWindow && (((TwindowInfo *)GetWRefCon(destWindow))->kind != cUserGroup);
destWindow = (WindowPtr) ((WindowPeek)destWindow)->nextWindow)
;
if (!destWindow)
return;
SubscribeSelected(info,(ListHandle)(info->data),destWindow);
}
/* HandleUnsubscribe unsubscribes the user from the selected newsgroups.
It is called when the user selects unsubscribe from the News menu.
*/
void HandleUnsubscribe(void)
{
TwindowInfo *info;
ListHandle theList;
Cell theCell;
Str255 groupName,wTitle;
short groupLen;
TGroup *curGroup,*prevGroup;
TWList *curChild;
Boolean doDelete;
if (!FrontWindow()) {
SysBeep(1);
return;
}
info = (TwindowInfo *)GetWRefCon(FrontWindow());
if (info->kind != cUserGroup)
return;
info->changed = true;
theList = (ListHandle) info->data;
SetPt(&theCell,0,0);
while (LGetSelect(true,&theCell,theList)) {
groupLen = 256;
LGetCell(groupName,&groupLen,theCell,theList);
doDelete = true;
for (curChild = info->childList; curChild!=nil && doDelete; curChild = curChild->next) {
GetWTitle(curChild->childWindow,wTitle);
p2cstr(wTitle);
if (strcmp(wTitle,groupName)==0)
doDelete = false;
}
if (doDelete) {
LDelRow(1,theCell.v,theList);
for (curGroup = prevGroup = (TGroup *)info->data2;
curGroup && strcmp(groupName,curGroup->name)!=0;
prevGroup = curGroup, curGroup = curGroup->next)
;
if (curGroup) {
if (curGroup==prevGroup)
info->data2 = (long)curGroup->next;
prevGroup->next = curGroup->next;
MyDisposPtr((Ptr)curGroup);
}
}
else theCell.v++;
}
}
/* CheckGroups compares the list of groups to those stored in the preferences
file. The groups which are new are then put into a new groups window.
*/
void CheckGroups(void)
{
extern TGroup *gGroupList;
extern short gNumGroups;
OSErr err;
short fRefNum;
char *groupBuf;
long groupLen = kMaxGroupLen;
char *current,*group;
long groupIndex;
short cmp;
Handle groupHandle = nil;
long numGroups = 0;
if ((err = FSOpen(kPrefName,BlessedFolder(),&fRefNum)) != noErr)
return;
if ((err = SetFPos(fRefNum,fsFromStart,sizeof(TPrefRec))) == noErr) {
groupBuf = (char *)MyNewPtr(groupLen);
if (MyMemErr() != noErr) {
FSClose(fRefNum);
return;
}
err = FSRead(fRefNum,&groupLen,(Ptr)groupBuf);
if (err != noErr && err != eofErr)
groupLen = 0;
groupBuf[groupLen] = '\0';
current = groupBuf;
groupIndex = 0;
group = GetNextGroup(¤t);
while (groupIndex < gNumGroups) {
GiveTime(0);
cmp = strcmp(group,gGroupList[groupIndex].name);
if (*group=='\0') {
AddNewGroup(&gGroupList[groupIndex],&groupHandle,&numGroups);
groupIndex++;
}
else if (cmp==0) {
group = GetNextGroup(¤t);
groupIndex++;
}
else if (cmp>0) {
AddNewGroup(&gGroupList[groupIndex],&groupHandle,&numGroups);
groupIndex++;
}
else if (cmp<0)
group = GetNextGroup(¤t);
}
MyDisposPtr(groupBuf);
MakeNewGroupWindow(groupHandle,numGroups,"\pNew Groups");
}
FSClose(fRefNum);
}
/* GetNextGroup parses the next group out of the preferences file
*/
char *GetNextGroup(char **current)
{
char *groupPos;
while (**current == CR || **current == LF)
(*current)++;
groupPos = *current;
while (**current && **current!=CR)
(*current)++;
if (**current)
*(*current)++ = '\0';
return groupPos;
}
/* AddNewGroup adds a new group (one which is not in the prefs file) to
the New Groups window.
*/
void AddNewGroup(TGroup *group,Handle *groupHandle,long *numGroups)
{
TGroup *groupList;
if (*groupHandle == nil) {
*groupHandle = MyNewHandle(sizeof(TGroup));
if (MyMemErr() != noErr)
return;
HLock(*groupHandle);
}
else {
HUnlock(*groupHandle);
MySetHandleSize(*groupHandle,GetHandleSize(*groupHandle)+sizeof(TGroup));
if (MyMemErr() != noErr)
return;
MoveHHi(*groupHandle);
HLock(*groupHandle);
}
groupList = (TGroup *) **groupHandle;
BlockMove((Ptr)group,(Ptr)&groupList[(*numGroups)++],sizeof(TGroup));
}
/* MakeNewGroupWindow creates a New Groups window to store the names of the
new newsgroups.
*/
void MakeNewGroupWindow(Handle groupHandle,long numGroups,char *windowName)
{
TwindowInfo *theInfo;
WindowPtr theWind;
GrafPtr savePort;
Cell theCell;
short i;
Point firstOffset;
char theName[256];
short cellLen;
Point thePt;
extern TPrefRec gPrefs;
if (numGroups==0)
return;
SetPt(&firstOffset,kOffLeft,kOffTop);
CloseStatusWindow();
theInfo = (TwindowInfo *) GetWRefCon(theWind = MakeNewWindow(cNewGroup,true,firstOffset,windowName));
StatusWindow("Adding New Groups...",0);
theInfo->numGroups = numGroups;
theInfo->parentGroup = nil;
theInfo->parentWindow = nil;
theInfo->childList = nil;
theInfo->data2 = (unsigned long) *groupHandle;
LDoDraw(false,(ListHandle)theInfo->data);
LAddRow(numGroups,0,(ListHandle)theInfo->data);
SetPt(&theCell,0,0);
for (i=0; i<numGroups; i++) {
strcpy(theName,((TGroup *)*groupHandle)[i].name);
if ((((TGroup *)*groupHandle)[i].lastMess - ((TGroup *)*groupHandle)[i].firstMess) <= 0) {
cellLen = strlen(theName)+2;
theName[cellLen-1] = 0xff;
}
else
cellLen = strlen(theName)+1;
LSetCell(theName,cellLen,theCell,(ListHandle)theInfo->data);
theCell.v++;
StatusWindow("Adding New Groups...",(short)(((float)(i+1)/(float)numGroups)*100));
GiveTime(0);
}
StatusWindow("Adding New Groups...",100);
GiveTime(0);
CloseStatusWindow();
LDoDraw(true,(ListHandle)theInfo->data);
SetPt(&thePt,0,0);
LSetSelect(true,thePt,(ListHandle)theInfo->data);
if (gPrefs.openWindowsZoomed)
ToggleZoom(theWind);
ShowWindow(theWind);
GetPort(&savePort);
SetPort(theWind);
InvalRect(&theWind->portRect);
SetPort(savePort);
}
/* WriteGroups writes the list of newsgroups out to the preferences file
before quitting the program.
*/
void WriteGroups(void)
{
extern TGroup *gGroupList;
extern short gNumGroups;
short fRefNum;
long i,count;
OSErr err;
StatusWindow("Writing group list...",0);
if ((err = FSOpen(kPrefName,BlessedFolder(),&fRefNum)) != noErr)
return;
err = SetFPos(fRefNum,fsFromStart,sizeof(TPrefRec));
if (err == noErr || err == eofErr) {
for (i=0; i<gNumGroups; i++) {
count = strlen(gGroupList[i].name);
FSWrite(fRefNum,&count,gGroupList[i].name);
count = 1;
FSWrite(fRefNum,&count,CRSTR);
GiveTime(0);
StatusWindow("Writing group list...",(short)(((float)(i+1)/(float)gNumGroups)*100));
}
StatusWindow("Writing group list...",100);
GiveTime(0);
}
FSClose(fRefNum);
}
/* MakeFollowUp creates a new article template for a follow-up back to
a newsgroup.
*/
void MakeFollowUp(void)
{
DialogPtr theDlg;
short item;
TwindowInfo *theInfo;
WindowPtr oldWind,theWind;
Point firstOffset;
GrafPtr savePort;
char subjectStr[256],groupStr[256],fromStr[256],distStr[256],refStr[256];
short iType;
Handle iHndl;
Rect iRect;
extern TPrefRec gPrefs;
Handle theHndl;
long offset,offset2;
if (!FrontWindow()) {
SysBeep(1);
return;
}
SetCursor(&QDARROW);
oldWind = FrontWindow();
SetPt(&firstOffset,0,0);
GetPort(&savePort);
SetPort(oldWind);
LocalToGlobal(&firstOffset);
SetPort(savePort);
if (CautionAlert(kPostAlert,nil) != okButton)
return;
SetCursor(&QDARROW);
theDlg = GetNewDialog(kPostDlg,nil,(WindowPtr)-1);
OutlineOK(theDlg);
theInfo = (TwindowInfo *) GetWRefCon(oldWind);
theHndl = (Handle) TEGetText((TEHandle)theInfo->data);
HLock(theHndl);
/* copy subject field */
offset = Munger(theHndl,0L,"Subject: ",9L,nil,0L);
offset2 = Munger(theHndl,offset,CRSTR,1L,nil,0L);
if (offset2 > offset && (offset2-offset) < 255 ) {
strcpy(subjectStr,"Re: ");
if (strncmp( (*theHndl)+offset+9,"Re: ",4) == 0)
offset += 4;
BlockMove( (*theHndl)+offset+9,(Ptr) (subjectStr+4),(offset2-offset-9));
subjectStr[offset2-offset-9+4] = '\0';
c2pstr(subjectStr);
GetDItem(theDlg,5,&iType,&iHndl,&iRect);
SetIText(iHndl,subjectStr);
}
/* copy newsgroups field */
offset = Munger(theHndl,0L,"Newsgroups: ",12L,nil,0L);
offset2 = Munger(theHndl,offset,CRSTR,1L,nil,0L);
if (offset > 0 && offset2 > 0 && (offset2-offset) < 255 ) {
BlockMove( (*theHndl)+offset+12,(Ptr) groupStr,(offset2-offset-12));
groupStr[offset2-offset-12] = '\0';
c2pstr(groupStr);
GetDItem(theDlg,3,&iType,&iHndl,&iRect);
SetIText(iHndl,groupStr);
}
/* copy distribution field */
offset = Munger(theHndl,0L,"Distribution: ",14L,nil,0L);
offset2 = Munger(theHndl,offset,CRSTR,1L,nil,0L);
if (offset > 0 && offset2 > 0 && (offset2-offset) < 255 ) {
BlockMove( (*theHndl)+offset+14,(Ptr) distStr,(offset2-offset-14));
distStr[offset2-offset-14] = '\0';
c2pstr(distStr);
GetDItem(theDlg,4,&iType,&iHndl,&iRect);
SetIText(iHndl,distStr);
}
HUnlock(theHndl);
GetDItem(theDlg,6,&iType,&iHndl,&iRect);
SetIText(iHndl,c2pstr(gPrefs.fullName));
GetDItem(theDlg,7,&iType,&iHndl,&iRect);
SetIText(iHndl,c2pstr(gPrefs.organization));
GetDItem(theDlg,8,&iType,&iHndl,&iRect);
SetIText(iHndl,c2pstr(gPrefs.address));
SelIText(theDlg,3,32767,32767);
do
ModalDialog(CmdKeyFilter,&item);
while (item != okButton && item != cancelButton);
GetDItem(theDlg,3,&iType,&iHndl,&iRect);
GetIText(iHndl,groupStr);
p2cstr(groupStr);
GetDItem(theDlg,4,&iType,&iHndl,&iRect);
GetIText(iHndl,distStr);
p2cstr(distStr);
GetDItem(theDlg,5,&iType,&iHndl,&iRect);
GetIText(iHndl,subjectStr);
GetDItem(theDlg,6,&iType,&iHndl,&iRect);
GetIText(iHndl,gPrefs.fullName);
p2cstr(gPrefs.fullName);
GetDItem(theDlg,7,&iType,&iHndl,&iRect);
GetIText(iHndl,gPrefs.organization);
p2cstr(gPrefs.organization);
GetDItem(theDlg,8,&iType,&iHndl,&iRect);
GetIText(iHndl,gPrefs.address);
p2cstr(gPrefs.address);
strcpy(fromStr,gPrefs.address);
strcat(fromStr," (");
strcat(fromStr,gPrefs.fullName);
strcat(fromStr,")");
DisposDialog(theDlg);
if (item == cancelButton)
return;
theInfo = (TwindowInfo *) GetWRefCon(theWind = MakeNewWindow(cPostMessage,true,firstOffset,subjectStr));
theInfo->changed = true;
IncludeQuote(oldWind,theWind,refStr);
AddHeader("Path: ",gPrefs.address,theWind);
AddHeader("From: ",fromStr,theWind);
AddHeader("Newsgroups: ",groupStr,theWind);
AddHeader("Distribution: ",distStr,theWind);
AddHeader("Subject: ",(char *)p2cstr(subjectStr),theWind);
AddHeader("References:",refStr,theWind);
AddHeader("Organization: ",gPrefs.organization,theWind);
AddHeader("","",theWind);
ShowWindow(theWind);
GetPort(&savePort);
SetPort(theWind);
RedoControls(theWind);
FixText(theWind);
InvalRect(&theWind->portRect);
SetPort(savePort);
}
/* MakeRespond creates a new message template for an e-mail response to
a news article.
*/
void MakeRespond(void)
{
DialogPtr theDlg;
short item;
TwindowInfo *theInfo;
WindowPtr oldWind,theWind;
Point firstOffset;
GrafPtr savePort;
char recipStr[256],subjectStr[256],fromStr[256],refStr[256];
short iType;
Handle iHndl,theHndl;
Rect iRect;
extern TPrefRec gPrefs;
long offset,offset2,offset3;
if (!FrontWindow()) {
SysBeep(1);
return;
}
SetCursor(&QDARROW);
oldWind = FrontWindow();
SetPt(&firstOffset,0,0);
GetPort(&savePort);
SetPort(oldWind);
LocalToGlobal(&firstOffset);
SetPort(savePort);
SetCursor(&QDARROW);
theDlg = GetNewDialog(kRespDlg,nil,(WindowPtr)-1);
OutlineOK(theDlg);
theInfo = (TwindowInfo *) GetWRefCon(oldWind);
theHndl = (Handle) TEGetText((TEHandle)theInfo->data);
HLock(theHndl);
/* copy subject field */
offset = Munger(theHndl,0L,"Subject: ",9L,nil,0L);
offset2 = Munger(theHndl,offset,CRSTR,1L,nil,0L);
if (offset2 > offset && (offset2-offset) < 255 ) {
strcpy(subjectStr,"Re: ");
if (strncmp( (*theHndl)+offset+9,"Re: ",4) == 0)
offset += 4;
BlockMove( (*theHndl)+offset+9,(Ptr) (subjectStr+4),(offset2-offset-9));
subjectStr[offset2-offset-9+4] = '\0';
c2pstr(subjectStr);
GetDItem(theDlg,4,&iType,&iHndl,&iRect);
SetIText(iHndl,subjectStr);
}
/* copy recipient field */
offset = Munger(theHndl,0L,"From: ",6L,nil,0L);
offset2 = Munger(theHndl,offset,"(",1L,nil,0L);
offset3 = Munger(theHndl,offset,CRSTR,1L,nil,0L);
if (offset2 < 0 || offset3 < offset2)
offset2 = offset3;
if (offset > 0 && offset2 > 0 && (offset2-offset) < 255 ) {
BlockMove( (*theHndl)+offset+6,(Ptr) recipStr,(offset2-offset-6));
recipStr[offset2-offset-6] = '\0';
c2pstr(recipStr);
GetDItem(theDlg,3,&iType,&iHndl,&iRect);
SetIText(iHndl,recipStr);
}
GetDItem(theDlg,5,&iType,&iHndl,&iRect);
SetIText(iHndl,c2pstr(gPrefs.fullName));
GetDItem(theDlg,6,&iType,&iHndl,&iRect);
SetIText(iHndl,c2pstr(gPrefs.organization));
GetDItem(theDlg,7,&iType,&iHndl,&iRect);
SetIText(iHndl,c2pstr(gPrefs.address));
HUnlock(theHndl);
SelIText(theDlg,3,32767,32767);
do
ModalDialog(CmdKeyFilter,&item);
while (item != okButton && item != cancelButton);
GetDItem(theDlg,3,&iType,&iHndl,&iRect);
GetIText(iHndl,recipStr);
p2cstr(recipStr);
GetDItem(theDlg,4,&iType,&iHndl,&iRect);
GetIText(iHndl,subjectStr);
GetDItem(theDlg,5,&iType,&iHndl,&iRect);
GetIText(iHndl,gPrefs.fullName);
p2cstr(gPrefs.fullName);
GetDItem(theDlg,6,&iType,&iHndl,&iRect);
GetIText(iHndl,gPrefs.organization);
p2cstr(gPrefs.organization);
GetDItem(theDlg,7,&iType,&iHndl,&iRect);
GetIText(iHndl,gPrefs.address);
p2cstr(gPrefs.address);
strcpy(fromStr,gPrefs.address);
strcat(fromStr," (");
strcat(fromStr,gPrefs.fullName);
strcat(fromStr,")");
DisposDialog(theDlg);
if (item == cancelButton)
return;
theInfo = (TwindowInfo *) GetWRefCon(theWind = MakeNewWindow(cSendMessage,true,firstOffset,subjectStr));
theInfo->changed = true;
IncludeQuote(oldWind,theWind,refStr);
AddHeader("From: ",fromStr,theWind);
AddHeader("To: ",recipStr,theWind);
AddHeader("Subject: ",(char *)p2cstr(subjectStr),theWind);
AddHeader("References:",refStr,theWind);
AddHeader("Organization: ",gPrefs.organization,theWind);
AddHeader("","",theWind);
ShowWindow(theWind);
GetPort(&savePort);
SetPort(theWind);
RedoControls(theWind);
FixText(theWind);
InvalRect(&theWind->portRect);
SetPort(savePort);
}
/* MakePost creates a new article template for a new posting to a user-
specified newsgroup.
*/
void MakePost(void)
{
DialogPtr theDlg;
short item;
TwindowInfo *theInfo;
WindowPtr theWind;
Point firstOffset;
short iType;
Handle iHndl;
Rect iRect;
char subjectStr[256],groupStr[256],fromStr[256],distStr[256];
GrafPtr savePort;
extern TPrefRec gPrefs;
SetCursor(&QDARROW);
if (CautionAlert(kPostAlert,nil) != okButton)
return;
SetCursor(&QDARROW);
theDlg = GetNewDialog(kPostDlg,nil,(WindowPtr)-1);
OutlineOK(theDlg);
GetDItem(theDlg,6,&iType,&iHndl,&iRect);
SetIText(iHndl,c2pstr(gPrefs.fullName));
GetDItem(theDlg,7,&iType,&iHndl,&iRect);
SetIText(iHndl,c2pstr(gPrefs.organization));
GetDItem(theDlg,8,&iType,&iHndl,&iRect);
SetIText(iHndl,c2pstr(gPrefs.address));
SelIText(theDlg,3,32767,32767);
do
ModalDialog(CmdKeyFilter,&item);
while (item != okButton && item != cancelButton);
GetDItem(theDlg,3,&iType,&iHndl,&iRect);
GetIText(iHndl,groupStr);
p2cstr(groupStr);
GetDItem(theDlg,4,&iType,&iHndl,&iRect);
GetIText(iHndl,distStr);
p2cstr(distStr);
GetDItem(theDlg,5,&iType,&iHndl,&iRect);
GetIText(iHndl,subjectStr);
GetDItem(theDlg,6,&iType,&iHndl,&iRect);
GetIText(iHndl,gPrefs.fullName);
p2cstr(gPrefs.fullName);
GetDItem(theDlg,7,&iType,&iHndl,&iRect);
GetIText(iHndl,gPrefs.organization);
p2cstr(gPrefs.organization);
GetDItem(theDlg,8,&iType,&iHndl,&iRect);
GetIText(iHndl,gPrefs.address);
p2cstr(gPrefs.address);
strcpy(fromStr,gPrefs.address);
strcat(fromStr," (");
strcat(fromStr,gPrefs.fullName);
strcat(fromStr,")");
DisposDialog(theDlg);
if (item == cancelButton)
return;
SetPt(&firstOffset,kOffLeft,kOffTop);
theInfo = (TwindowInfo *) GetWRefCon(theWind = MakeNewWindow(cPostMessage,true,firstOffset,subjectStr));
theInfo->changed = true;
AddHeader("Path: ",gPrefs.address,theWind);
AddHeader("From: ",fromStr,theWind);
AddHeader("Newsgroups: ",groupStr,theWind);
AddHeader("Distribution: ",distStr,theWind);
AddHeader("Subject: ",(char *)p2cstr(subjectStr),theWind);
AddHeader("Organization: ",gPrefs.organization,theWind);
AddHeader("","",theWind);
ShowWindow(theWind);
GetPort(&savePort);
SetPort(theWind);
RedoControls(theWind);
FixText(theWind);
InvalRect(&theWind->portRect);
SetPort(savePort);
}
/* IncludeQuote indents and includes the article to which the user is responding
in the new article template.
*/
void IncludeQuote(WindowPtr parentWindow,WindowPtr newWindow,char *refStr)
{
Handle text,oldText;
long teLength;
TwindowInfo *info;
long offset,offset2;
char article[256],sender[256];
char mungeStr[256];
info = (TwindowInfo *) GetWRefCon(parentWindow);
oldText = text = (Handle) TEGetText((TEHandle)info->data);
teLength = (**((TEHandle)info->data)).teLength;
info = (TwindowInfo *) GetWRefCon(newWindow);
strcpy(mungeStr,CRSTR);
strcat(mungeStr,"Message-ID:");
offset = Munger(oldText,0,mungeStr,12L,nil,0L);
if (offset >= 0) {
offset += 12;
offset2 = Munger(oldText,offset,CRSTR,1L,nil,0L);
if (offset2 < 0)
offset2 = offset;
strncpy( article,(char *)*oldText+offset,offset2-offset);
*(article+offset2-offset) = '\0';
}
else
strcpy(article,"");
strcpy(mungeStr,CRSTR);
strcat(mungeStr,"From:");
offset = Munger(oldText,0,mungeStr,6L,nil,0L);
if (offset >= 0) {
offset += 6;
offset2 = Munger(oldText,offset,CRSTR,1L,nil,0L);
if (offset2 < 0)
offset2 = offset;
strncpy( sender,(char *)*oldText+offset,offset2-offset);
*(sender+offset2-offset) = '\0';
}
else
strcpy(sender,"...");
strcpy(mungeStr,CRSTR);
strcat(mungeStr,"References:");
offset = Munger(oldText,0,mungeStr,12L,nil,0L);
if (offset >= 0) {
offset += 12;
offset2 = Munger(oldText,offset,CRSTR,1L,nil,0L);
if (offset2 < 0)
offset2 = offset;
strncpy( refStr,(char *)*oldText+offset,offset2-offset);
*(refStr+offset2-offset) = '\0';
}
else
strcpy(refStr,"");
strcat(refStr,article);
if (MyHandToHand(&text) != noErr)
return;
MySetHandleSize(text,teLength);
if (MyMemErr() != noErr)
return;
strcpy(mungeStr,CRSTR);
strcat(mungeStr,CRSTR);
offset = Munger(text,0,mungeStr,2L,nil,0L);
offset = Munger(text,0,nil,offset,"*",0L);
strcpy(mungeStr,CRSTR);
strcat(mungeStr,"> ");
while ( (offset = Munger(text,offset,CRSTR,1L,mungeStr,3L)) >= 0)
;
offset = Munger(text,0,nil,0L,"In article",10L);
offset = Munger(text,offset,nil,0L,article,strlen(article));
offset = Munger(text,offset,nil,0L,",",1L);
offset = Munger(text,offset,nil,0L,sender,strlen(sender));
offset = Munger(text,offset,nil,0L," writes:",8L);
teLength = GetHandleSize(text);
HLock(text);
TESetText(*text,teLength,(TEHandle)info->data);
TESetSelect(0L,0L,(TEHandle)info->data);
HUnlock(text);
MyDisposHandle(text);
}
/* AddHeader adds a header of name hName and contents hContents to the
TextEdit field in window newWindow.
*/
void AddHeader(char *hName,char *hContents,WindowPtr newWindow)
{
TEHandle theTE;
theTE = (TEHandle) ((TwindowInfo *)GetWRefCon(newWindow))->data;
TEInsert(hName,strlen(hName),theTE);
TEInsert(hContents,strlen(hContents),theTE);
TEInsert(CRSTR,1,theTE);
}
/* If user authentication were important, this routine would check to make
sure that the "From:" header was not changed before allowing the article
to be posted.
*/
Boolean CheckHeader(TwindowInfo *info)
{
#pragma unused (info)
/* no user authentication, so don't have to check header */
return true;
}