This is ArticleSet.m in view mode; [Download] [Up]
#import "Alexandra.h" #import "Article.h" #import "ArticleSet.h" #import "NewsgroupSet.h" #import "Newsgroup.h" #import "ArticleViewControl.h" #import "Composer.h" #import "ColumnMatrix.h" #import "ArticleSetMatrix.h" #include <assert.h> #import <misckit/MiscMailApp.h> #import <misckit/MiscString.h> #import <misckit/MiscAppDefaults.h> #import "response_codes.h" #import "plain-subject.h" #import "MatrixScroller.h" #import "descriptors.h" @implementation ArticleSet - init { currentNewsgroup=nil; unselAction=@selector(clear); [super init]; return self; } - awakeFromNib { char buf1[255]; sprintf(buf1,"SortType %s",[nntpServer serverName]); currentSortType=[NXApp defaultIntValue:buf1]; return self; } - free { [Composer killComposerForServer:nntpServer]; return [super free]; } - loadGroup:(Newsgroup *)aNewsgroup { int i,j; Article *anArticle; if(aNewsgroup==nil) return self; currentNewsgroup=aNewsgroup; //get article list myMList=[aNewsgroup articleList]; [myMatrix setMatrixCellList:myMList]; //choose articles to show. Here: all unread j=[myMList count]; for(i=0;i<j;i++){ anArticle=[myMList objectAt:i]; if([anArticle isRead]) [anArticle unsetTag]; else [anArticle setTag]; } [myMatrix setAutodisplay:NO]; [[myMatrix loadMatrix] scrollUp]; [[myMatrix setAutodisplay:YES] display]; [self sync]; return self; } - selectArticle:sender { int statusCode; Article *oldSelection; [[myMatrix window] makeFirstResponder:myMatrix]; assert(myMList!=NULL); oldSelection=currentSelection; [self syncAndReturnList:NO]; if(oldSelection==currentSelection) return self; if(numSelCells==1){ statusCode=[theArticleViewControl loadArticle:currentSelection fromGroup:[[theNewsgroupSet currentSelection] stringValue]]; if(statusCode!=OK_BODY){ if(statusCode==-1) return self; //[myMList removeObject:currentSelection]; if([currentSelection isRead]==FALSE){ [[theNewsgroupSet currentSelection] incNumberUnreadArticles:-1]; [theNewsgroupSet redisplayMatrix]; } [myMatrix perform:@selector(removeInvalidCell:) with:currentSelection afterDelay:0.0 cancelPrevious:YES]; return self; } if([currentSelection isRead]==FALSE){ [currentSelection setRead]; [[theNewsgroupSet currentSelection] incNumberUnreadArticles:-1]; [theNewsgroupSet redisplayMatrix]; } } [myMatrix display]; return self; } - showAll:sender { if((currentNewsgroup==nil) || (myMList==nil)) return self; [myMList makeObjectsPerform:@selector(setTag)]; [[myMatrix reloadMatrix] display]; [myMatrix setButtonTitle:"All Articles"]; return self; } - showUnread:sender { int i,j; int oldNumSelCells; if((currentNewsgroup==NULL) || (myMList==NULL)) return self; j=[myMList count]; for(i=0;i<j;i++){ Article* anArticle; anArticle=[myMList objectAt:i]; if([anArticle isRead]==TRUE) [anArticle unsetTag]; else [anArticle setTag]; } if(currentSelection!=nil) [currentSelection setTag]; [[myMatrix reloadMatrix] display]; oldNumSelCells=numSelCells; [self sync]; if((oldNumSelCells!=1)&&(numSelCells==1)){ currentSelection=nil; numSelCells=0; [self selectArticle:self]; } [myMatrix setButtonTitle:"Unread Articles"]; return self; } - markSelectionReadOrUnread:(BOOL)flag { /*flag==TRUE <=> Mark unread */ Article* anArticle; int delta; List *articleList=nil; int i,j; if(currentNewsgroup==NULL) return self; articleList=[myMatrix getCurrSelections]; j=[articleList count]; delta=0; for(i=0;i<j;i++){ anArticle=[articleList objectAt:i]; if([anArticle isRead]==flag){ if(flag==FALSE){ [anArticle setRead]; delta-=1; } else{ [anArticle setUnread]; delta+=1; } } } if(delta!=0){ [[theNewsgroupSet currentSelection] incNumberUnreadArticles:delta]; [theNewsgroupSet redisplayMatrix]; [myMatrix display]; } [articleList free]; return self; } - markRead:sender { [self markSelectionReadOrUnread:FALSE]; return self; } - markUnread:sender { [self markSelectionReadOrUnread:TRUE]; return self; } - followupToSelection:sender { if(currentSelection!=nil){ if([self postToSelectedNG:self]!=nil) [theComposer followup:self]; } return self; } - postToSelectedNG:sender { List *selList; int i,j; EM_DURING selList=[[theNewsgroupSet theMatrix] getCurrSelections]; // warum muss den eine Gruppe ausgewÙhlt sein? EM_CONDERROR(([selList count]==0),ECOMPNeedGroup,NULL,NULL); // See if posting is possible in general if([nntpServer canPost]==FALSE) EM_ERROR(ECOMPNoPosting,NULL,NULL); // See if you can post to all groups in list j=[selList count]; for(i=0;i<j;i++){ char p=[[selList objectAt:i] postable]; if(p=='n') EM_ERROR(ECOMPNoPostingToGroup,[[selList objectAt:i] stringValue],NULL); } // O.K. theComposer=[Composer newWindowForServer:nntpServer]; [theComposer preparePostTo:selList selArticle:currentSelection inView:theArticleViewControl]; EM_EMPTYHANDLER [selList free]; return self; } - clearMatrix { currentNewsgroup=nil; myMList=nil; [myMatrix setMatrixCellList:nil]; [[myMatrix loadMatrix] display]; [[myMatrix window] flushWindow]; [self sync]; return self; } - (const char *)stringValue { return ptr_to_articlebody; } - forwardArticle:sender { NXStream *aStream; int len,maxlen; id subjectStr=[[MiscString init] alloc]; const char *oldSubjectPtr; BOOL is_reply; id mailer; if((currentSelection==nil)||(currentNewsgroup==nil)){ NXRunAlertPanel("ALEXANDRA","No article selected.",NULL,NULL,NULL); return self; } mailer=[MiscMailApp localMailer]; if(mailer==nil){ NXRunAlertPanel("ALEXANDRA","Can't reach mail application.",NULL,NULL,NULL); return self; } //O.K. first get the articles body aStream=NXOpenMemory(NULL,0,NX_WRITEONLY); NXPrintf(aStream,"Forwarded Article %s\n",[currentSelection header]->fieldBody[MSG_ID]); NXPrintf(aStream,"Newsgroup %s\n",[currentNewsgroup stringValue]); NXPrintf(aStream,"From %s\n\n",[currentSelection header]->fieldBody[FROM]); [theArticleViewControl writeBody:aStream]; NXGetMemoryBuffer(aStream,&ptr_to_articlebody,&len,&maxlen); //Compose subject oldSubjectPtr=plain_subject((char *)[currentSelection stringValue],&is_reply); if(is_reply) [subjectStr setStringValue:"Re: "]; [subjectStr strcat:oldSubjectPtr]; // Open Compose window in mailer [mailer sendMailTo:nil subject:currentSelection body:self]; NXCloseMemory(aStream,NX_FREEBUFFER); [subjectStr free]; return self; } - replyByMail:sender { NXStream *aStream; int len,maxlen; MiscString *to,*subject; char *r; BOOL dummy; id mailer; if((currentSelection==nil)||(currentNewsgroup==nil)){ NXRunAlertPanel("ALEXANDRA","No article selected.",NULL,NULL,NULL); return self; } mailer=[MiscMailApp localMailer]; if(mailer==nil){ NXRunAlertPanel("ALEXANDRA","Can't reach mail application.",NULL,NULL,NULL); return self; } //O.K. first get the articles body aStream=NXOpenMemory(NULL,0,NX_WRITEONLY); NXPrintf(aStream,"In article %s, you wrote:\n",[currentSelection header]->fieldBody[MSG_ID]); [theArticleViewControl writeQuotedText:aStream]; NXGetMemoryBuffer(aStream,&ptr_to_articlebody,&len,&maxlen); //Make Subject string subject=[[MiscString alloc] init]; [subject setStringValue:"Re: "]; [subject strcat:plain_subject([currentSelection header]->fieldBody[SUBJECT], &dummy)]; //Make To to=[[MiscString alloc] init]; r=[currentSelection header]->fieldBody[REPLY_TO]; if((r==NULL)||(r[0]=='\0')) r=[currentSelection header]->fieldBody[FROM]; [to setStringValue:r]; // Open Compose window in mailer [mailer sendMailTo:to subject:subject body:self]; NXCloseMemory(aStream,NX_FREEBUFFER); [to free]; [subject free]; return self; } - cancelArticle:sender { char *messageID; char *mailAddress; NXStream *articlestream; if(currentSelection==nil) return nil; if ((messageID=[currentSelection header]->fieldBody[MSG_ID]) == NULL) return nil; mailAddress = [[FromHeaderController new] validFromAddress]; if(!mailAddress) return self; //Post articlestream = NXOpenMemory(NULL, 0, NX_WRITEONLY); NXPrintf(articlestream,"Newsgroups: %s\nSubject: cancel\nControl: cancel %s\nFrom: %s\n\ncancel\n",[currentSelection header]->fieldBody[NEWSGROUPS], messageID, mailAddress); NXSeek(articlestream, (long)0,NX_FROMSTART); [nntpServer postArticle:articlestream]; NXCloseMemory(articlestream,NX_FREEBUFFER); free(mailAddress); return(self); } - setArticleSortType:(int)type { char buf[255]; int oldType; id selNewsgroup; sprintf(buf,"SortType %s",[nntpServer serverName]); oldType=[NXApp defaultIntValue:buf]; if(oldType!=type){ currentSortType=type; [NXApp setDefault:buf toInt:type]; if((selNewsgroup=[theNewsgroupSet currentSelection])!=nil) if([selNewsgroup resortIfNeeded:type]){ [myMatrix reloadMatrix]; [myMatrix display]; } } return self; } - sortArticlesByNumber:sender { [self setArticleSortType:SORT_BY_NUMBER]; return self; } - sortArticlesByDate:sender { [self setArticleSortType:SORT_BY_DATE]; return self; } - sortArticlesBySubject:sender { [self setArticleSortType:SORT_BY_SUBJECT]; return self; } - sortArticlesByName:sender { [self setArticleSortType:SORT_BY_REAL_NAME]; return self; } - catchUpThreadAt:(int)index { int i,j; id anArticle; const char *thread_subject; int m=0; BOOL dummy; thread_subject=plain_subject([[myMatrix cellAt:index :0] header]->fieldBody[SUBJECT],&dummy); for(i=0,j=[myMList count];i<j;i++){ anArticle=[myMList objectAt:i]; if(!strcmp(plain_subject([anArticle header]->fieldBody[SUBJECT],&dummy),thread_subject)){ if(![anArticle isRead]){ [anArticle setRead]; m++; } } } if(m>0) [[theNewsgroupSet currentSelection] incNumberUnreadArticles:-1*m]; return self; } - skipThreadAndUpOrDown:(int)delta { int i=[myMatrix selectedRow]; int a,b,s; if(i<0){ NXRunAlertPanel("ALEXANDRA","No article selected.",NULL,NULL,NULL); return self; } [self catchUpThreadAt:i]; if(delta!=0){ [myMatrix getNumRows:&a numCols:&b]; s=i+delta; while((s>=0) && (s<a)){ id anArticle=[myMatrix cellAt:s :0]; if(![anArticle isRead]){ [myMatrix selectCellAt:s :0]; [self selectArticle:self]; [myMatrix scrollCellToVisible:s upperOffset:((delta==-1)? 1.5:0.0) lowerOffset:((delta==1)? 1.5:0.0)]; break; } s+=delta; } } [myMatrix display]; [theNewsgroupSet redisplayMatrix]; return self; } - skipThreadAndUp:sender { return [self skipThreadAndUpOrDown:-1]; } - skipThreadAndDown:sender { return [self skipThreadAndUpOrDown:1]; } - (const char *)stringValueForCellAt:(int)index { int h=[NXApp defaultIntValue:"findGeneralScope"]; if((h>=0)&&(h<XOVER_COUNT)){ char *s=[[myMList objectAt:index] header]->fieldBody[h]; if(s!=NULL) return s; } return ""; } - (BOOL)selectArticleWithMsgid:(const char *)msgid { int i,j; for(i=0,j=[myMList count];i<j;i++){ const char *aMsgid=[[myMList objectAt:i] header]->fieldBody[MSG_ID]; if(aMsgid && !strcmp(aMsgid,msgid)) return [self selectArticleWithNumber:[[myMList objectAt:i] number]]; } return FALSE; } - (BOOL)selectArticleWithNumber:(long)snumber; { int i,j; for(i=0,j=[myMList count];i<j;i++){ id aCell=[myMList objectAt:i]; if([aCell number]==snumber){ if(![aCell isTaged]) [self showAll:self]; return [myMatrix selectArticleWithNumber:snumber]; } } return FALSE; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.