home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------
- #
- # NewsWatcher - Macintosh NNTP Client Application
- #
- # Written by Steven Falkenburg
- # ©1990 Apple Computer, Inc.
- #
- #-----------------------------------------------------------
- #
- # commands.c
- #
- # This file contains user interface routines which are
- # called in response to user actions recorded in userint.c
- #
- #-----------------------------------------------------------*/
-
- #pragma segment userint
-
- #include "compat.h"
- #include <CType.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 <Scrap.h>
- #include <Resources.h>
- #include <Script.h>
- #include <Printing.h>
- #include <Strings.h>
- #endif
-
- #include <StdLib.h>
- #include <String.h>
-
- #include "nntp.h"
- #include "userint.h"
- #include "newsprocess.h"
- #include "ScrollStuff.h"
- #include "netstuff.h"
- #include "miscstuff.h"
- #include "printstuff.h"
- #include "commands.h"
-
- #ifdef NNTPNEWS
- #include "NNTPLow.h"
- #else
- #include "HFSNTPLow.h"
- #endif
-
-
- /* adds a child window to the windowlist of a parent
- Windows with associated child windows will close
- their children when closed
- */
-
- void AddChild(WindowPtr parent,WindowPtr child)
- {
- TwindowInfo *parentInfo;
- TWList *newChild;
-
- parentInfo = (TwindowInfo *) GetWRefCon(parent);
-
- newChild = (TWList *) MyNewPtr(sizeof(TWList));
- if (MyMemErr() != noErr)
- return;
- newChild->childWindow = child;
- newChild->next = parentInfo->childList;
- parentInfo->childList = newChild;
- }
-
-
- /* Removes a child window from the windowlist of a parent
- */
-
- void RemoveChild(WindowPtr parent,WindowPtr child)
- {
- TwindowInfo *parentInfo;
- TWList *current,*prev;
-
- parentInfo = (TwindowInfo *) GetWRefCon(parent);
- for (current = prev = parentInfo->childList;
- current != nil && current->childWindow!=child;
- prev = current,current = current->next)
- ;
- if (current) {
- prev->next = current->next;
- if (prev == current)
- parentInfo->childList = current->next;
- MyDisposPtr((Ptr)current);
- }
- }
-
-
- /* MakeGroupList takes a list of groups and a List Manager
- handle. The groups are sorted and added to the list.
- */
-
- void MakeGroupList(ListHandle theList,short numGroups,TGroup *groupList)
- {
- long i;
- Cell theCell;
- char theName[256];
- short cellLen;
-
- StatusWindow("Sorting Groups...",-1);
- qsort(groupList, numGroups, sizeof(TGroup), MyCompare);
-
- StatusWindow("Building List...",0);
- GiveTime(0);
-
- LDoDraw(false,theList);
- LAddRow(numGroups,0,theList);
- for (i=0; i<numGroups; i++) {
-
- strcpy(theName,groupList[i].name);
- if ((groupList[i].lastMess - groupList[i].firstMess) <= 0) {
- cellLen = strlen(theName)+2;
- theName[cellLen-1] = 0xff;
- }
- else
- cellLen = strlen(theName)+1;
-
- SetPt(&theCell,0,i);
- LSetCell(theName,cellLen,theCell,theList);
- StatusWindow("Building List...",(short)(((float)(i+1)/(float)numGroups)*100)+1);
- GiveTime(0);
- }
- StatusWindow("Building List...",100);
- GiveTime(0);
- LDoDraw(true,theList);
- SetCursor(&QDARROW);
- }
-
-
- /* MyCompare is a comparison routine used in the call to
- qsort() above. It does a simple string compare, and
- gives time to background applications.
- */
-
- int MyCompare(TGroup *one,TGroup *two)
- {
- GiveTime(0);
- return strcmp(one->name,two->name);
- }
-
-
- /* HandleGroupSelect is called in response to a mouse
- down event in a main group window (not a user group
- window). It opens a subject window containing the
- names of all articles in that group.
- */
-
- void HandleGroupSelect(Cell theCell,WindowPtr window)
- {
- TwindowInfo *theInfo;
- WindowPtr theWind;
- Str255 tmpStr,tmpTitle;
- TGroup *groupList,*theGroup;
- GrafPtr savePort;
- Cell thePt;
- Point firstOffset;
- WindowPtr tmpWindow;
- char groupStr[256];
- short groupLen;
-
- extern TPrefRec gPrefs;
-
- SetPt(&firstOffset,0,0);
- GetPort(&savePort);
- SetPort(window);
- LocalToGlobal(&firstOffset);
- SetPort(savePort);
-
- theInfo = (TwindowInfo *) GetWRefCon(window);
- groupList = (TGroup *) theInfo->data2;
-
- groupLen = 256;
- LGetCell(groupStr,&groupLen,theCell,(ListHandle)theInfo->data);
-
- if (!FindGroup(theInfo,groupStr,&theGroup)) {
- SysBeep(1);
- return;
- }
-
- strcpy((char *)tmpStr,theGroup->name);
- c2pstr((char *)tmpStr);
- for (tmpWindow = FrontWindow(); tmpWindow != nil; tmpWindow = (WindowPtr) ((WindowPeek)tmpWindow)->nextWindow) {
- GetWTitle(tmpWindow,tmpTitle);
- if (EqualString(tmpStr,tmpTitle,true,true)) {
- SelectWindow(tmpWindow);
- return;
- }
- }
-
- if (theGroup->firstMess > 0 &&
- theGroup->lastMess> 0 &&
- theGroup->lastMess - theGroup->firstMess >= 0) {
- theInfo = (TwindowInfo *) GetWRefCon(theWind = MakeNewWindow(cSubject,true,firstOffset,(char *)tmpStr));
- theInfo->parentGroup = nil;
- theInfo->childList = nil;
- theInfo->parentWindow = nil;
- InitSubjectList(theInfo);
- StatusWindow("Getting Subject List...",0);
- AddToSubjectList(theInfo,theGroup->name,
- theGroup->firstMess,theGroup->lastMess);
- StatusWindow("Getting Subject List...",100);
- GiveTime(0);
- CloseStatusWindow();
- 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);
- }
- else
- SysBeep(1);
- }
-
-
- /* HandleUserGroupSelect is called in response to a mouse
- down in a user group window. It opens a window containing
- the subjects of all unread articles in that group.
- */
-
- void HandleUserGroupSelect(Cell theCell,WindowPtr window)
- {
- TwindowInfo *theInfo;
- WindowPtr theWind;
- Str255 tmpStr,tmpTitle;
- TGroup *theGroup;
- GrafPtr savePort;
- ListHandle theList;
- char groupName[256];
- short groupLen = 255;
- TReadRec *read;
- WindowPtr parent;
- Point firstOffset;
- WindowPtr tmpWindow;
- extern TPrefRec gPrefs;
-
- SetPt(&firstOffset,0,0);
- GetPort(&savePort);
- SetPort(window);
- LocalToGlobal(&firstOffset);
- SetPort(savePort);
-
- theInfo = (TwindowInfo *)GetWRefCon(window);
- theInfo->changed = true;
-
- theList = (ListHandle) theInfo->data;
- LGetCell(groupName,&groupLen,theCell,theList);
-
- strcpy((char *)tmpStr,groupName);
- c2pstr((char *)tmpStr);
-
- /* make sure group window is not already open */
-
- for (tmpWindow = FrontWindow(); tmpWindow != nil; tmpWindow = (WindowPtr) ((WindowPeek)tmpWindow)->nextWindow) {
- GetWTitle(tmpWindow,tmpTitle);
- if (EqualString(tmpStr,tmpTitle,true,true)) {
- SelectWindow(tmpWindow);
- return;
- }
- }
-
- /* search linked info list for group info */
-
-
- if (!FindGroup(theInfo,groupName,&theGroup) || !theGroup->read) {
- SysBeep(1);
- return;
- }
-
- strcpy((char *)tmpStr,theGroup->name);
-
- parent = window;
- theInfo = (TwindowInfo *) GetWRefCon(theWind = MakeNewWindow(cSubject,true,firstOffset,(char *)c2pstr((char *)tmpStr)));
- theInfo->parentGroup = theGroup;
- theInfo->parentWindow = parent;
- theInfo->childList = nil;
- AddChild(parent,theWind);
-
- InitSubjectList(theInfo);
-
- StatusWindow("Getting Subject List...",0);
- for (read = theGroup->read; read!=nil; read = read->next)
- AddToSubjectList(theInfo,theGroup->name,read->firstRead,read->lastRead);
- StatusWindow("Getting Subject List...",100);
- GiveTime(0);
- CloseStatusWindow();
-
- SetPt(&theCell,0,0);
- LSetSelect(true,theCell,(ListHandle)theInfo->data);
-
- if (gPrefs.openWindowsZoomed)
- ToggleZoom(theWind);
- ShowWindow(theWind);
-
- GetPort(&savePort);
- SetPort(theWind);
- InvalRect(&theWind->portRect);
- SetPort(savePort);
- }
-
-
- /* FindGroup locates a user group record within the linked list
- of user groups, given the name of the group.
- */
-
- Boolean FindGroup(TwindowInfo *info,char *groupName,TGroup **theGroup)
- {
- *theGroup = nil;
-
- if (info->kind == cGroup || info->kind == cNewGroup)
- *theGroup = bsearch(groupName,(TGroup *)info->data2,info->numGroups,sizeof(TGroup),SearchCompare);
- else if (info->kind == cUserGroup)
- for (*theGroup = (TGroup *)info->data2;
- *theGroup != nil && strcmp((*theGroup)->name,groupName)!=0;
- *theGroup = (*theGroup)->next)
- ;
-
- return (*theGroup != nil);
- }
-
-
- /* SearchCompare is used in the bsearch() call within FindGroup.
- It is used to compare each instance of group name to the
- name provided.
- */
-
- int SearchCompare(char *key,TGroup *member)
- {
- return (strcmp(key,member->name));
- }
-
-
- /* HandleSubjectSelect is called in response to a mouse down in a
- subject list window. In this case, the article whose subject
- was selected is opened in an article window.
- */
-
- void HandleSubjectSelect(Cell theCell,WindowPtr wind)
- {
- TwindowInfo *info,*articleInfo;
- char newsGroup[256],numStr[256],title[256];
- char *tmpStr,*tmpStr2;
- long number;
- short nameLen;
- short i;
- Str255 tmpTitle1,tmpTitle2;
- WindowPtr tmpWindow;
-
- info = (TwindowInfo *) GetWRefCon(wind);
- GetWTitle(wind,newsGroup);
- p2cstr(newsGroup);
-
- nameLen = 256;
- LGetCell(title,&nameLen,theCell,(ListHandle)info->data);
-
- strcpy((char *)tmpTitle1,title);
- c2pstr((char *)tmpTitle1);
- for (tmpWindow = FrontWindow(); tmpWindow != nil; tmpWindow = (WindowPtr) ((WindowPeek)tmpWindow)->nextWindow) {
- GetWTitle(tmpWindow,tmpTitle2);
- if (EqualString(tmpTitle1,tmpTitle2,true,true)) {
- SelectWindow(tmpWindow);
- return;
- }
- }
-
- for (tmpStr = numStr,tmpStr2 = title+1;
- *tmpStr2 != ' ' && *tmpStr2 != '\0';
- *tmpStr++ = *tmpStr2++)
- ;
- *tmpStr = '\0';
- c2pstr(numStr);
- StringToNum((StringPtr)numStr,&number);
- p2cstr(numStr);
-
- if (info->parentGroup && title[0] != '√') {
- nameLen = strlen(title)+2;
- *title = '√';
- 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 = true;
- else
- SysBeep(1);
- }
- OpenArticle(newsGroup,numStr,title,wind,cMessage);
-
- if (info->parentGroup && info->parentWindow) {
- info = (TwindowInfo *)GetWRefCon(info->parentWindow);
- articleInfo = (TwindowInfo *)GetWRefCon(FrontWindow());
- MarkXrefsRead((TEHandle)articleInfo->data,(TGroup *)info->data2);
- }
- }
-
-
- /* OpenReferences opens up all articles which are referred to in
- the article contained in the frontmost window. The "References:"
- field is used to determine which articles should be fetched.
- */
-
- void OpenReferences(void)
- {
- TwindowInfo *info;
- Handle theText;
- long refOffset,endHeader,startReference,endReference;
- char title[256];
- char mungeText1[256];
- char mungeText2[256];
-
- if (!FrontWindow()) {
- SysBeep(1);
- return;
- }
-
- strcpy(mungeText1,CRSTR);
- strcat(mungeText1,"References:");
- strcpy(mungeText2,CRSTR);
- strcat(mungeText2,CRSTR);
-
- info = (TwindowInfo *)GetWRefCon(FrontWindow());
- if (info->kind != cMessage)
- return;
- theText = (Handle) TEGetText((TEHandle)info->data);
- if ((refOffset = Munger(theText,0,mungeText1,12L,nil,0L))>=0 &&
- refOffset < (endHeader = Munger(theText,0,mungeText2,2L,nil,0L))) {
- do {
- startReference = Munger(theText,refOffset,"<",1L,nil,0L);
- endReference = Munger(theText,refOffset,">",1L,nil,0L);
- if (startReference>=0 && endReference>=0 && endReference<endHeader) {
- HLock(theText);
- strncpy(title,(char *)((*theText)+startReference),endReference-startReference+1);
- title[endReference-startReference+1] = '\0';
- HUnlock(theText);
- OpenArticle(nil,title,title,nil,cMiscMessage);
- }
- refOffset = endReference+1;
- } while (startReference>=0 && endReference>=0 && endReference<endHeader);
- }
- }
-
-
- /* OpenArticle gets the text of an article, given the newsgroup,
- and article number or message-id. The article is fetched
- and placed in a new window created by the procedure call.
- */
-
- void OpenArticle(char *newsGroup,char *number,char *title,WindowPtr parent,short kind)
- {
- char *text;
- long length;
- WindowPtr theWindow;
- TwindowInfo *newInfo;
- GrafPtr savePort;
- TEHandle theTE;
- Point firstOffset;
- extern TPrefRec gPrefs;
-
- if (!FrontWindow()) {
- SysBeep(1);
- return;
- }
-
- SetPt(&firstOffset,0,0);
- GetPort(&savePort);
-
- if (parent == nil)
- SetPort(FrontWindow());
- else
- SetPort(parent);
- LocalToGlobal(&firstOffset);
- SetPort(savePort);
-
- GetPort(&savePort);
- theWindow = MakeNewWindow(kind,true,firstOffset,(char *)c2pstr(title));
- p2cstr(title);
-
- newInfo = (TwindowInfo *) GetWRefCon(theWindow);
- newInfo->parentWindow = parent;
- newInfo->childList = nil;
- SetPort(theWindow);
-
- theTE = (TEHandle)((TwindowInfo *)GetWRefCon(theWindow))->data;
-
- if (GetArticle(newsGroup,number,&text,&length,kMaxLength) == noErr) {
- if (length > 32000)
- length = 32000;
- TESetText(text,length,theTE);
- TESetSelect(0L,0L,theTE);
- if (gPrefs.openWindowsZoomed)
- DoZoom(theWindow,inZoomOut);
- ShowWindow(theWindow);
- RedoControls(theWindow);
- FixText(theWindow);
- InvalRect(&theWindow->portRect);
- }
- else
- DoCloseWindow(theWindow);
-
- SetPort(savePort);
- MyDisposPtr(text);
- }
-
-
- /* DoSelectAll is called in response to a Select-All menu command.
- If in a list manager window, all cells are hilited. If in a
- textedit window, the entire range of a message is hilited.
- */
-
- void DoSelectAll(void)
- {
- TwindowInfo *info;
- Cell theCell;
- ListHandle theList;
- TEHandle theTE;
-
- if (!FrontWindow()) {
- SysBeep(1);
- return;
- }
-
- info = (TwindowInfo *)GetWRefCon(FrontWindow());
- if (info->kind < cMessage) {
- theList = (ListHandle) info->data;
- SetPt(&theCell,0,0);
- do {
- LSetSelect(true,theCell,theList);
- } while (LNextCell(false,true,&theCell,theList));
- }
- else {
- theTE = (TEHandle) info->data;
- TESetSelect(0L,32767L,theTE);
- }
- }
-
-
- /* DoSearch is called in response to a search menu command.
- All currenly selected newsgroups are searched for a text
- string which is prompted for below. A user group window
- is created containing an entry for each of the selected
- group which matched the search, and the articles are
- placed in these groups.
- */
-
- void DoSearch(void)
- {
- TwindowInfo *info,*newInfo;
- ListHandle theList;
- Cell theCell,newCell;
- char cellData[256],headerTxt[256],searchTxt[256];
- short dataLen;
- TGroup *groupData,*prevGroup,*curGroup;
- DialogPtr theDlg;
- short item;
- WindowPtr searchWindow;
- short iType;
- Handle iHndl;
- Rect iRect;
- char *current;
-
- if (!FrontWindow()) {
- SysBeep(1);
- return;
- }
-
- /* display dialog asking what to search for */
-
- theDlg = GetNewDialog(kSearchDlg,nil,(WindowPtr)-1);
- OutlineOK(theDlg);
-
- GetDItem(theDlg,5,&iType,&iHndl,&iRect);
- SetDItem(theDlg,5,iType,(Handle) DrawPopUp,&iRect);
-
- do ModalDialog(PopUpFilter,&item);
- while (item != okButton && item != cancelButton);
-
- GetDItem(theDlg,3,&iType,&iHndl,&iRect);
- GetIText(iHndl,headerTxt);
- p2cstr(headerTxt);
- GetDItem(theDlg,4,&iType,&iHndl,&iRect);
- GetIText(iHndl,searchTxt);
- p2cstr(searchTxt);
-
- for (current = searchTxt; *current != '\0'; current++)
- *current = toupper(*current);
-
- DisposDialog(theDlg);
-
- if (item==cancelButton || *headerTxt=='\0' || *searchTxt=='\0')
- return;
-
- info = (TwindowInfo *) GetWRefCon(FrontWindow());
- theList = (ListHandle) info->data;
- searchWindow = NewGroupWindow("\pSearch Groups");
- newInfo = (TwindowInfo *) GetWRefCon(searchWindow);
- newInfo->changed = false;
- newInfo->diskFile[0] = '\0';
-
- SetPt(&theCell,0,0);
-
- while (LGetSelect(true,&theCell,theList)) {
- dataLen = 256;
- LGetCell(cellData,&dataLen,theCell,theList);
- if (FindGroup(info,cellData,&groupData)) {
- groupData = Subscribe(groupData,searchWindow,&newCell);
- if (groupData && groupData->read) {
- MyDisposPtr((Ptr)groupData->read);
- groupData->read = nil;
- if (!SearchAdd(headerTxt,searchTxt,groupData)) {
- LDelRow(1,newCell.v,(ListHandle)newInfo->data);
- for (curGroup = prevGroup = (TGroup *)newInfo->data2;
- curGroup && curGroup!=groupData;
- prevGroup = curGroup, curGroup = curGroup->next)
- ;
- if (curGroup == nil) {
- SysBeep(1);
- return;
- }
- prevGroup->next = nil;
- if (prevGroup == curGroup)
- newInfo->data2 = nil;
- MyDisposPtr((Ptr)groupData);
- }
- }
- theCell.v++;
- }
- }
- }
-
-
- /* DrawPopUp is the useritem procedure to draw a pop-up menu.
- This routine is called in response to update events for the
- pop-up menu area.
- */
-
- pascal void DrawPopUp(DialogPtr theDlg,short theItem)
- {
- #pragma unused (theItem)
- Rect iRect;
- short iType;
- Handle iHndl;
-
- GetDItem(theDlg,5,&iType,&iHndl,&iRect);
-
- /* draw the box and shadow */
-
- FrameRect(&iRect);
- MoveTo(iRect.right,iRect.top+2);
- LineTo(iRect.right,iRect.bottom);
- LineTo(iRect.left+2,iRect.bottom);
-
- /* draw the downward triangle */
-
- MoveTo(((iRect.left+iRect.right)/2)-5,((iRect.top+iRect.bottom)/2)-3);
- Line(8,0);
- Move(-1,1);
- Line(-6,0);
- Move(1,1);
- Line(4,0);
- Move(-1,1);
- Line(-2,0);
- Move(1,1);
- Line(0,0);
- }
-
-
- /* This routine is the dialog filter for the dialog box containing
- a pop-up menu.
- */
-
- pascal Boolean PopUpFilter(DialogPtr theDlg,EventRecord *ev,short *item)
- {
- char keyPressed;
- Point downLoc;
- MenuHandle popMenu;
- short iType;
- Handle iHndl;
- Rect iRect;
- long chosen;
- short choice;
- Str255 iString;
-
- *item = 0;
- switch (ev->what) {
- case keyDown:
- case autoKey:
- keyPressed = ev->message & charCodeMask;
- if (keyPressed == CR || keyPressed == 03) {
- *item = okButton;
- return true;
- }
- break;
- case mouseDown:
- SetPort(theDlg);
- downLoc = ev->where;
- GlobalToLocal(&downLoc);
- if (FindDItem(theDlg,downLoc)+1 == 5) {
- GetDItem(theDlg,5,&iType,&iHndl,&iRect);
- popMenu = GetMenu(kHeaderMenu);
- InsertMenu(popMenu,-1);
- downLoc.h = iRect.left;
- downLoc.v = iRect.top;
- LocalToGlobal(&downLoc);
- CalcMenuSize(popMenu);
- chosen = PopUpMenuSelect(popMenu,downLoc.v,downLoc.h,1);
- if (chosen) {
- choice = LoWord(chosen);
- GetItem(popMenu,choice,iString);
- GetDItem(theDlg,3,&iType,&iHndl,&iRect);
- SetIText(iHndl,iString);
- SelIText(theDlg,3,0,32767);
- }
- DisposeMenu(popMenu);
- }
- break;
- }
- return false;
- }
-
-
- /* SearchAdd is called once for each group being searched. It
- searches for matching articles. It returns true if one
- or more of the articles in the group matched the selection.
- */
-
- Boolean SearchAdd(char *headerName,char *headerContents, TGroup *groupData)
- {
- TSubject subjects[64];
- long numSubjects;
- long index,rFirst,rLast,firstUnread = 0,lastUnread = 0;
- OSErr err = noErr;
- Boolean gotOne = false;
- char statusStr[256];
-
- for (rFirst = groupData->firstMess; rFirst <= groupData->lastMess && err == noErr; rFirst += 64) {
- rLast = ((rFirst+63) > groupData->lastMess) ? groupData->lastMess : rFirst+63;
- err = GetMessages(groupData->name,rFirst,rLast,subjects,&numSubjects,headerName);
- strcpy(statusStr,"Searching group: ");
- strcat(statusStr,groupData->name);
- StatusWindow(statusStr,-1);
- if (err==noErr)
- for (index=0; index < numSubjects; index++) {
- if (MySearch(subjects[index].name,headerContents,strlen(subjects[index].name),strlen(headerContents)) == 0) {
- if (firstUnread == 0)
- firstUnread = lastUnread = subjects[index].number;
- else
- lastUnread = subjects[index].number;
- }
- else {
- if (firstUnread != 0) {
- MarkRead(firstUnread,lastUnread,groupData);
- gotOne = true;
- firstUnread = 0;
- }
- }
- MyDisposPtr(subjects[index].name);
- }
- }
- if (firstUnread != 0) {
- MarkRead(firstUnread,groupData->lastMess,groupData);
- gotOne = true;
- }
- return gotOne;
- }
-
-
- /* DoNarrowSelection is called in response to the Narrow Selection
- menu command. This routine displays a dialog box, where the
- user enters a string which must be contained in all of the
- entries in a group or subject list.
- */
-
- void DoNarrowSelection(void)
- {
- DialogPtr theDlg;
- short item;
- short iType;
- Handle iHndl;
- Rect iRect;
- Str255 theText;
- TwindowInfo *info;
- char filterCopy[256];
- short filterCopyLen,index;
-
- if (!FrontWindow()) {
- SysBeep(1);
- return;
- }
-
- info = (TwindowInfo *) GetWRefCon(FrontWindow());
- filterCopyLen = info->filterLen;
- strncpy(filterCopy,info->filter,filterCopyLen);
-
- theDlg = GetNewDialog(kNarrowDlg,nil,(WindowPtr)-1);
- OutlineOK(theDlg);
-
- if (info->filterLen > 0) {
- BlockMove(info->filter,theText+1,info->filterLen);
- theText[0] = info->filterLen;
- GetDItem(theDlg,3,&iType,&iHndl,&iRect);
- SetIText(iHndl,theText);
- SelIText(theDlg,3,32000,32000);
- }
-
- do {
- ModalDialog(NarrowFilter,&item);
- SetCursor(&QDARROW);
- } while (item != okButton && item != cancelButton);
-
- if (item == cancelButton) {
- if (info->filterLen > 0)
- EndSearch(info);
- if (filterCopyLen > 0) {
- NewSearch(info,filterCopy[0]);
- for (index=1; index<filterCopyLen; index++)
- NarrowSearch(info,filterCopy[index]);
- }
- }
-
- DisposDialog(theDlg);
- }
-
-
- /* NarrowFilter is the dialog filter for the narrow selection
- search dialog box.
- */
-
- pascal Boolean NarrowFilter(DialogPtr theDialog,EventRecord *theEvent,short *itemHit)
- {
- TwindowInfo *info;
- char theChar;
- unsigned long saveBits;
-
- if (theEvent->what == keyDown || theEvent->what == autoKey) {
- saveBits = (theEvent->message & 0xFFFFFF00);
- theChar = toupper(theEvent->message & charCodeMask);
- theEvent->message = saveBits | theChar;
- SelIText(theDialog,3,32000,32000);
- info = (TwindowInfo *) GetWRefCon((WindowPtr)((WindowPeek)FrontWindow())->nextWindow); /* window after dlog */
-
- switch (theChar) {
- case CR:
- *itemHit = 1;
- return true;
- break;
- case 0x08:
- if (info->filterLen > 0)
- WidenSearch(info);
- break;
- default:
- if (info->filterLen == 0)
- NewSearch(info,theChar);
- else
- NarrowSearch(info,theChar);
- break;
- }
- }
- return false;
- }
-
-
- /* NewSearch is called by the narrow selection filter to start
- a new narrowing search. It creates a secondary list manager
- list which is visible over top of the main list. Entries
- which match are added to this list.
- */
-
- void NewSearch(TwindowInfo *info,char theChar)
- {
- Cell theCell,newCell;
- char cellData[256];
- short dataLen;
- ListHandle newList;
- WindowPtr theWindow;
-
- theWindow = (WindowPtr)((WindowPeek)FrontWindow())->nextWindow;
- info->narrowList = (ListHandle) info->data;
- newList = NewList(theWindow);
- info->data = (Handle) newList;
- LActivate(false,info->narrowList);
- (**newList).lClikLoop = (**(info->narrowList)).lClikLoop;
-
- info->filter[info->filterLen++] = theChar;
-
- SetPt(&theCell,0,0);
- SetPt(&newCell,0,0);
- while (PtInRect(theCell,&(**(info->narrowList)).dataBounds) &&
- LSearch(info->filter,info->filterLen,MySearch,&theCell,info->narrowList)) {
- LAddRow(1,newCell.v,newList);
- dataLen = 256;
- LGetCell(cellData,&dataLen,theCell,info->narrowList);
- LSetCell(cellData,dataLen,newCell,newList);
- theCell.v++;
- newCell.v++;
- }
- LDoDraw(true,newList);
-
- ForceUpdate();
- }
-
-
- /* WidenSearch is called when the backspace key is pressed in
- the narrow search dialog box. It removes constraint on the
- list and adds entries where necessary
- */
-
- void WidenSearch(TwindowInfo *info)
- {
- Cell theCell,newCell;
- char cellData[256];
- short dataLen;
- ListHandle theList;
-
- info->filterLen--;
-
- if (info->filterLen == 0)
- EndSearch(info);
- else {
-
- /* rebuild list */
-
- theList = (ListHandle) info->data;
-
- LDoDraw(false,theList);
- LDelRow(0,0,theList);
- LAddRow(1,0,theList);
-
- SetPt(&theCell,0,0);
- SetPt(&newCell,0,0);
- while (PtInRect(theCell,&(**(info->narrowList)).dataBounds) &&
- LSearch(info->filter,info->filterLen,MySearch,&theCell,info->narrowList)) {
- LAddRow(1,newCell.v,theList);
- dataLen = 256;
- LGetCell(cellData,&dataLen,theCell,info->narrowList);
- LSetCell(cellData,dataLen,newCell,theList);
- theCell.v++;
- newCell.v++;
- }
- LDoDraw(true,theList);
- ForceUpdate();
- }
- }
-
-
- /* NarrowSearch is called by the narrowing search filter when
- a non-backspace key is pressed in the dialog. It searches
- the secondary list for entries which may be removed.
- */
-
- void NarrowSearch(TwindowInfo *info,char theChar)
- {
- Cell theCell;
- char data[256];
- short dataLen;
- Boolean notDone = true;
- ListHandle theList;
-
- theList = (ListHandle) info->data;
-
- info->filter[info->filterLen++] = theChar;
-
- LDoDraw(false,theList);
- SetPt(&theCell,0,0);
- do {
- dataLen = 255;
- LGetCell(data,&dataLen,theCell,theList);
- if (PtInRect(theCell,&(**theList).dataBounds) &&
- MySearch(data,info->filter,dataLen,info->filterLen) != 0) {
- LDelRow(1,theCell.v,theList);
- if (theCell.v != 0)
- theCell.v--;
- }
- else notDone = LNextCell(false,true,&theCell,theList);
- } while (notDone);
- LDoDraw(true,theList);
- ForceUpdate();
- }
-
-
- /* EndSearch is called when a narrowing search has been completed.
- */
- void EndSearch(TwindowInfo *info)
- {
- ListHandle doneList;
- WindowPtr theWindow;
- GrafPtr savePort;
-
- theWindow = (WindowPtr)((WindowPeek)FrontWindow())->nextWindow;
-
- doneList = (ListHandle) info->data;
- LActivate(true,info->narrowList);
- LDispose(doneList);
- info->data = (Handle) info->narrowList;
- info->narrowList = nil;
- info->filter[0] = '\0';
- info->filterLen = 0;
- GetPort(&savePort);
- SetPort(theWindow);
- SizeContents(theWindow->portRect.right-theWindow->portRect.left,theWindow->portRect.bottom-theWindow->portRect.top,theWindow);
- SetPort(savePort);
- ForceUpdate();
- }
-
-
- /* ForceUpdate is called by the narrowing search routines to
- invalidate the list area, forcing an update event to be
- generated for the area.
- */
-
- void ForceUpdate(void)
- {
- WindowPtr theWindow;
- GrafPtr savePort;
-
- theWindow = (WindowPtr)((WindowPeek)FrontWindow())->nextWindow;
-
- GetPort(&savePort);
- SetPort(theWindow);
- InvalRect(&theWindow->portRect);
- SetPort(savePort);
- HandleUpdates(theWindow);
- }
-
-
- /* MySearch is the search procedure used to match entries
- for the narrowing search routines.
- */
-
- pascal short MySearch(Ptr aPtr,Ptr bPtr,short aLen,short bLen)
- {
- short index;
- char *aUpper;
-
- GiveTime(0);
-
- aUpper = (char *)NewPtr(aLen);
- for (index = 0; index < aLen; index++)
- aUpper[index] = toupper(aPtr[index]);
-
- for (index = 0; index < aLen; index++) {
- if ((aLen-index) < bLen) {
- DisposPtr((Ptr)aUpper);
- return 1;
- }
- if (strncmp(aUpper+index,bPtr,bLen) == 0) {
- DisposPtr((Ptr)aUpper);
- return 0;
- }
- }
- DisposPtr((Ptr)aUpper);
- return 1;
- }
-
-
- /* DoRot is called in response to the Do Rot-13 menu command. It
- encrypts/decrypts an entire message, or just a selection using
- the Rot-13 method common on USENET news groups.
- */
-
- void DoRot(void)
- {
- GrafPtr theWindow;
- TwindowInfo *info;
- TEHandle theTE;
- GrafPtr savePort;
- short i,sStart,sEnd;
-
- if (!FrontWindow()) {
- SysBeep(1);
- return;
- }
-
- info = (TwindowInfo *)GetWRefCon(theWindow = FrontWindow());
- if (info->kind < cMessage)
- return;
-
- theTE = (TEHandle)info->data;
- HLock((**theTE).hText);
-
- sStart = (**theTE).selStart;
- sEnd = (**theTE).selEnd;
- if (sStart == sEnd) {
- sStart = 0;
- sEnd = (**theTE).teLength;
- }
-
- for (i=sStart; i<= sEnd; i++)
- if (isalpha((*(**theTE).hText)[i]))
- (*(**theTE).hText)[i] += (toupper((*(**theTE).hText)[i]) > 'M') ? -13 : 13;
-
- HUnlock((**theTE).hText);
- GetPort(&savePort);
- SetPort(theWindow);
- InvalRect(&theWindow->portRect);
- SetPort(savePort);
- }
-
-
- /* DoNextMessage is called in response to the menu command of the same
- name. It closes the current message window, and opens the next
- message in the current group. If the group has no more messages,
- the next group is opened, along with the first message in that
- group. This is sort of a hack.
- */
-
- void DoNextMessage(void)
- {
- TwindowInfo *info;
- Cell theCell;
- ListHandle theList;
- WindowPtr parentWind;
- Str255 cellData;
- short dataLen;
-
- if (!FrontWindow()) {
- SysBeep(1);
- return;
- }
-
- info = (TwindowInfo *) GetWRefCon(FrontWindow());
- SetPt(&theCell,0,0);
-
- switch (info->kind) {
- case cUserGroup:
- theList = (ListHandle) info->data;
- if (LGetSelect(true,&theCell,theList)) {
- dataLen = 256;
- LGetCell(cellData,&dataLen,theCell,theList);
- if ((unsigned char) cellData[dataLen-1] == 0xff) {
- LSetSelect(false,theCell,theList);
- if (LNextCell(false,true,&theCell,theList)) {
- LSetSelect(true,theCell,theList);
- LAutoScroll(theList);
- }
- DoNextMessage();
- }
- else {
- info = (TwindowInfo *) GetWRefCon(FrontWindow());
- if (info->kind == cUserGroup)
- HandleUserGroupSelect(theCell,FrontWindow());
- LSetSelect(false,theCell,theList);
- if (LNextCell(false,true,&theCell,theList)) {
- LSetSelect(true,theCell,theList);
- LAutoScroll(theList);
- }
- }
- }
- else
- SysBeep(1);
- break;
- case cSubject:
- theList = (ListHandle) info->data;
- if (LGetSelect(true,&theCell,theList)) {
- HandleSubjectSelect(theCell,FrontWindow());
- }
- else {
- if (parentWind = info->parentWindow) {
- DoCloseWindow(FrontWindow());
- BringToFront(parentWind);
- DoNextMessage();
- }
- else SysBeep(1);
- }
- break;
- case cMessage:
- if (parentWind = info->parentWindow) {
- DoCloseWindow(FrontWindow());
- BringToFront(parentWind);
- info = (TwindowInfo *) GetWRefCon(FrontWindow());
- theList = (ListHandle) info->data;
- LGetSelect(true,&theCell,theList);
- LSetSelect(false,theCell,theList);
- if (LNextCell(false,true,&theCell,theList))
- LSetSelect(true,theCell,theList);
- DoNextMessage();
- }
- else
- SysBeep(1);
- break;
- default:
- SysBeep(1);
- }
- }
-
-
- /* ReadMessage is called in response to a mouse down in a list
- manager window. This routine dispatches the open command
- to the routine appropriate to the type of window.
- */
-
- void ReadMessage(WindowPtr theWindow)
- {
- Cell theCell;
- TwindowInfo *theInfo;
-
- if (!theWindow) {
- SysBeep(1);
- return;
- }
-
- theInfo = (TwindowInfo *) GetWRefCon(theWindow);
-
- SetPt(&theCell,0,0);
- while (LGetSelect(true,&theCell,(ListHandle)theInfo->data)) {
- switch (theInfo->kind) {
- case cGroup:
- case cNewGroup:
- HandleGroupSelect(theCell,theWindow);
- break;
- case cUserGroup:
- HandleUserGroupSelect(theCell,theWindow);
- break;
- case cSubject:
- HandleSubjectSelect(theCell,theWindow);
- break;
- }
- theCell.v++;
- }
- }
-
-
- /* ToggleCheck toggles the state of a checkbox in the
- active dialog box.
- */
-
- void ToggleCheck(DialogPtr theDlg,short item)
- {
- Handle iHndl;
- short iType;
- Rect iRect;
- short value;
-
- GetDItem(theDlg,item,&iType,&iHndl,&iRect);
- value = (GetCtlValue((ControlHandle)iHndl) == 1) ? 0 : 1;
- SetCtlValue((ControlHandle)iHndl,value);
- }
-
-
- /* GetCheck gets the state of a checkbox in the active
- dialog box.
- */
-
- Boolean GetCheck(DialogPtr theDlg,short item)
- {
- Handle iHndl;
- short iType;
- Rect iRect;
-
- GetDItem(theDlg,item,&iType,&iHndl,&iRect);
- return (GetCtlValue((ControlHandle)iHndl) == 1);
- }
-
-
- /* SetValue sets the value of an editText dialog item
- to an integer value.
- */
-
- void SetValue(DialogPtr theDlg,short item,short value)
- {
- Handle iHndl;
- short iType;
- Rect iRect;
- Str255 valStr;
-
- NumToString(value,valStr);
- GetDItem(theDlg,item,&iType,&iHndl,&iRect);
- SetIText(iHndl,valStr);
-
- }
-
-
- /* GetValue gets the value of an editText dialog item
- as an integer value.
- */
-
- short GetValue(DialogPtr theDlg,short item)
- {
- Handle iHndl;
- short iType;
- Rect iRect;
- Str255 valStr;
- long value;
-
- GetDItem(theDlg,item,&iType,&iHndl,&iRect);
- GetIText(iHndl,valStr);
- StringToNum(valStr,&value);
- return (short)value;
- }
-
-
- /* SetPrefs allows the user to set several preferences for the
- NewsWatcher program. The routine uses a dialog box to
- display and let the user edit these values.
- */
-
- void SetPrefs(TPrefRec *prefs)
- {
-
- DialogPtr theDlg;
- short item;
-
- theDlg = GetNewDialog(kPrefDlg,nil,(WindowPtr)-1);
- OutlineOK(theDlg);
-
- if (prefs->openWindowsZoomed)
- ToggleCheck(theDlg,3);
- if (prefs->parentWindows)
- ToggleCheck(theDlg,4);
- if (prefs->mostRecentFirst)
- ToggleCheck(theDlg,5);
- SetValue(theDlg,6,prefs->maxFetch);
- SetValue(theDlg,7,prefs->windowOffset.h);
- SetValue(theDlg,8,prefs->windowOffset.v);
-
- do {
- ModalDialog(CmdKeyFilter,&item);
- if (item >= 3 && item <= 5)
- ToggleCheck(theDlg,item);
- }
- while (item != okButton && item != cancelButton);
-
- if (item == okButton) {
- prefs->openWindowsZoomed = GetCheck(theDlg,3);
- prefs->parentWindows = GetCheck(theDlg,4);
- prefs->mostRecentFirst = GetCheck(theDlg,5);
- prefs->maxFetch = GetValue(theDlg,6);
- prefs->windowOffset.h = GetValue(theDlg,7);
- prefs->windowOffset.v = GetValue(theDlg,8);
- }
-
- DisposDialog(theDlg);
- }