This is KillFile.m in view mode; [Download] [Up]
#import "Alexandra.h"
#import "KillFile.h"
#import "descriptors.h"
#import "Article.h"
#import "NNTP.h"
#import "ArticleSet.h"
#import "ArticleSetMatrix.h"
#import "MainWindowControl.h"
#import "NntpPanelControl.h"
#import <misckit/MiscAppDefaults.h>
#import "plain-subject.h"
#import "MatrixScroller.h"
#define MODE_AUTHOR 1
#define MODE_THREAD 0
#define MODE_ASK 2
#define MODE_NOTHING -1
@implementation KillFile
- setPath
{
const char *home=NXHomeDirectory();
const char *servername=[nntpServer serverName];
path=(char *)malloc((strlen(home)+strlen(servername)+25)*sizeof(char));
strcpy(path,home);
strcat(path,"/Library/Alexandra");
mkdir(path,448);
strcat(path,"/");
strcat(path,servername);
mkdir(path,448);
strcat(path,"/");
return self;
}
- init
{
newsgroupTable=[[HashTable alloc] initKeyDesc:"*" valueDesc:"@"];
authorTable=NULL;
return self;
}
- free
{
[self saveAndFree];
if(path!=NULL)
free(path);
return [super free];
}
- getAuthorTable
{
char buf[255],buf2[255];
FILE *fd;
char *fullPath;
char tableFile[]="KILLAUTHORS";
if(authorTable!=NULL)
return authorTable;
fullPath=(char *)malloc(strlen(path)+strlen(tableFile)+2);
strcpy(fullPath,path);
strcat(fullPath,tableFile);
authorTable=[[HashTable alloc] initKeyDesc:"*" valueDesc:"i"];
fd=fopen(fullPath,"r");
if(fd!=NULL){
while(fgets(buf,255,fd),((buf[0]!='.')&&(buf[0]!='\0'))){
if(buf[0]!='A')
continue;
*buf2='\0';
sscanf(buf,"A %[^\n]\n",buf2);
if(strlen(buf2)>2)
[authorTable insertKey:(const void *)NXCopyStringBuffer(buf2) value:(void *)1];
}
fclose(fd);
}
free(fullPath);
return authorTable;
}
- getThreadTableFor:(const char *)newsgroup
{
id groupTable=[newsgroupTable valueForKey:newsgroup];
char *fullPath;
FILE *fd;
char buf[255],buf2[255];
long *s;
long seconds;
struct timeval tp;
struct timezone tzp;
long dist;
if(newsgroup==NULL){
NXLogError("KillFile: Newsgroup with NULL pointer as name");
return groupTable;
}
gettimeofday(&tp,&tzp);
dist=[NXApp defaultIntValue:"KillfileExpire"];
if(dist==0)
dist=30;
dist=dist*24*60*60;
if(groupTable!=nil)
return groupTable;
groupTable=[[HashTable alloc] initKeyDesc:"*" valueDesc:"!"];
[newsgroupTable insertKey:NXCopyStringBuffer(newsgroup) value:groupTable];
fullPath=(char *)malloc(strlen(path)+strlen(newsgroup)+2);
strcpy(fullPath,path);
strcat(fullPath,newsgroup);
fd=fopen(fullPath,"r");
if(fd!=NULL){
while(fgets(buf,255,fd) && ((buf[0]!='.')&&(buf[0]!='\0'))){
if(buf[0]!='S')
continue;
*buf2='\0';
sscanf(buf,"S %[^\t]\t%ld",buf2,&seconds);
if(strlen(buf2)>0 && tp.tv_sec-seconds<dist){
s=(long *)malloc(sizeof(long));
*s=seconds;
[groupTable insertKey:(const void *)NXCopyStringBuffer(buf2) value:(void *)s];
}
}
fclose(fd);
}
free(fullPath);
return groupTable;
}
- killUnkillAuthor:(BOOL)doKill author:(const char *)author
{
id aTable=[self getAuthorTable];
if((author==NULL)||(author[0]=='\0')) return nil;
if(doKill==TRUE){
if(![aTable isKey:author]){
char *name=NXCopyStringBuffer(author);
[aTable insertKey:(const void *)name value:(void *)1];
}
}
else
[aTable removeKey:author];
return self;
}
- killUnkillThread:(BOOL)doKill :(char *)subject newsgroup:(id)group
{
char *val;
id subjectTable=[self getThreadTableFor:[group stringValue]];
struct timeval tp;
struct timezone tzp;
BOOL dummy;
gettimeofday(&tp,&tzp);
if((subject==NULL)||(subject[0]=='\0')) return nil;
val=plain_subject(subject,&dummy);
if((val==NULL)||(val[0]=='\0')) return nil;
if((doKill==TRUE)&&([subjectTable isKey:val]==FALSE)){
long *s=(long *)malloc(sizeof(long));
*s=tp.tv_sec;
[subjectTable insertKey:(const void *)NXCopyStringBuffer(val) value:(void *)s];
}
else{
[subjectTable removeKey:val];
free(val);
}
return self;
}
- filterArticles:(id)newsgroup andReloadMatrix:(BOOL)reload
{
int i,j;
id aList=[newsgroup articleList];
id subjectTable=[self getThreadTableFor:[newsgroup stringValue]];
id aTable=[self getAuthorTable];
int num_unread_killed=0;
struct timeval tp;
struct timezone tzp;
BOOL subjectFits,authorFits;
BOOL dummy;
int rememberNextPos=0;
id nextCell=nil;
id selectedCell=[[theArticleSet theMatrix] selectedCell];
gettimeofday(&tp,&tzp);
j=[aList count];
for(i=0;i<j;i++){
id anArticle=[aList objectAt:i];
const char *subject,*lsubject;
const char *name;
headerDesc *h;
if([anArticle isKilled])
continue;
h=[anArticle header];
if(!h){
NXLogError("KillFile.m: article with NULL pointer header");
continue;
}
lsubject=h->fieldBody[SUBJECT];
if(!lsubject){
NXLogError("KillFile: Article with NULL pointer as subject");
continue;
}
subject=plain_subject((char *)lsubject,&dummy);
name=[anArticle realName];
subjectFits=((subject!=NULL)&&([subjectTable isKey:subject]));
authorFits=((name!=NULL)&&([aTable isKey:name]));
if( subjectFits || authorFits){
if([anArticle isRead]==FALSE)
num_unread_killed++;
[anArticle kill];
if(subjectFits)
*(long *)[subjectTable valueForKey:subject]=tp.tv_sec;
if((rememberNextPos==0)&&(selectedCell==anArticle))
rememberNextPos=1;
}
else
if((rememberNextPos==1)&&([anArticle isTaged])){
rememberNextPos=2;
nextCell=anArticle;
}
}
if(reload==TRUE){
id matrix=[theArticleSet theMatrix];
[matrix reloadMatrix];
[matrix display];
[theArticleSet sync];
if(num_unread_killed>0){
[newsgroup incNumberUnreadArticles:-1*num_unread_killed];
[[theNGSet theMatrix] display];
}
if(nextCell!=nil){
int row,col;
[matrix getRow:&row andCol:&col ofCell:nextCell];
[matrix selectCellAt:row :col];
[theArticleSet selectArticle:self];
[matrix scrollCellToVisible:row upperOffset:1.5 lowerOffset:1.5];
}
}
return self;
}
- saveAndFree
{
FILE *fd;
char *fullPath;
char tableFile[]="KILLAUTHORS";
BOOL success=TRUE;
if(authorTable!=nil){
fullPath=(char *)malloc(strlen(path)+strlen(tableFile)+2);
strcpy(fullPath,path);
strcat(fullPath,tableFile);
if([authorTable count]>0){
fd=fopen(fullPath,"w");
if(fd==NULL)
success=FALSE;
else{
char *name;
int *value;
NXHashState state=[authorTable initState];
while([authorTable nextState:&state key:(const void **)&name value:(void **)&value]){
fprintf(fd,"A %s\n",name);
free(name);
}
fprintf(fd,".\n");
fclose(fd);
}
free(fullPath);
}
else
remove(fullPath);
free(fullPath);
[authorTable free];
}
if([newsgroupTable count]>0){
char *gname;
id groupTable;
NXHashState ngstate=[newsgroupTable initState];
while([newsgroupTable nextState:&ngstate key:(const void **)&gname value:(void **)&groupTable]){
fullPath=(char *)malloc(strlen(path)+strlen(gname)+2);
strcpy(fullPath,path);
strcat(fullPath,gname);
if([groupTable count]>0){
fd=fopen(fullPath,"w");
if(fd==NULL)
success=FALSE;
else{
char *subject;
long *value;
NXHashState gstate=[groupTable initState];
while([groupTable nextState:&gstate key:(const void **)&subject value:(void **)&value]){
fprintf(fd,"S %s\t%ld\n",subject,*value);
free(subject);
free(value);
}
fprintf(fd,".\n");
fclose(fd);
}
}
else
remove(fullPath);
free(fullPath);
[groupTable free];
}
}
[newsgroupTable free];
if(success==FALSE)
NXLogError("Can't save killfile.\n");
return self;
}
- killAuthor:sender
{
[self killSelectionMode:MODE_AUTHOR];
return self;
}
- killThread:sender
{
if([theArticleSet currentSelection]==nil){
NXRunAlertPanel("ALEXANDRA","No article selected.",NULL,NULL,NULL);
return nil;
}
if(![NXApp defaultBoolValue:"DoNotConfirmAKill"])
if(NXRunAlertPanel("ALEXANDRA","Do you really want to kill this thread?",NULL,"Cancel",NULL)==NX_ALERTALTERNATE)
return self;
[self killSelectionMode:MODE_THREAD];
return self;
}
#define ALERT_KILLWHAT NXLocalString("Do you want to kill all articles of this thread or all articles written by this author?",NULL,"Frage was ge-kill-t werden soll.")
#define ALERT_NOARTICLE NXLocalString("You must select an Article first.",NULL,"Alert Panel falls Kill aufgerufen wird ohne daû ein Artikel selektiert ist.")
#define STRG_CANCEL NXLocalString("Cancel",NULL,"In Alert-Panels")
#define STRG_AUTHOR NXLocalString("Author",NULL,"In Kill-Alert-Panel")
#define STRG_THREAD NXLocalString("Thread",NULL,"In Kill-Alert-Panel")
- kill:sender;
{
int killMode,ret;
if([theArticleSet currentSelection]==nil)
{
NXRunAlertPanel("ALEXANDRA",ALERT_NOARTICLE,STRG_CANCEL,NULL,NULL);
return nil;
}
killMode=[NXApp defaultIntValue:DEFAULT_KILL_BEHAVIOUR];
if(killMode==MODE_ASK)
{
ret=NXRunAlertPanel("ALEXANDRA", ALERT_KILLWHAT, STRG_THREAD,
STRG_AUTHOR, STRG_CANCEL);
if(ret==NX_ALERTDEFAULT)
killMode=MODE_THREAD;
else if(ret==NX_ALERTALTERNATE)
killMode=MODE_AUTHOR;
else
killMode=MODE_NOTHING;
}
if(killMode!=MODE_NOTHING)
[self killSelectionMode:killMode];
return self;
}
- killSelectionMode:(int)mode
{
id currentNewsgroup,currentArticle;
char *subject;
if((currentNewsgroup=[theNGSet currentSelection])==nil)
return nil;
if((currentArticle=[theArticleSet currentSelection])==nil)
return nil;
if(mode==MODE_THREAD){
subject=[currentArticle header]->fieldBody[SUBJECT];
if((subject==NULL)||(subject[0]=='\0'))
return nil;
[self killUnkillThread:YES :subject newsgroup:currentNewsgroup];
[self filterArticles:currentNewsgroup andReloadMatrix:YES];
}
else{
const char *name=[currentArticle realName];
if((name==NULL)||(name[0]=='\0'))
return nil;
[self killUnkillAuthor:YES author:name];
[self filterArticles:currentNewsgroup andReloadMatrix:YES];
}
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.