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.