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.