/* ARISA - Main pack and packlist functions * Copyright (C) 2003, 2004 Carl Ritson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "arisa.h" #include #include #include #include #include #define MAX_SCAN_DEPTH 32 #define MAX_SCAN_DEPTH_STR "32" static pack_t *in_list(pack_t **packs, int no_packs, pack_t *p, const char *file) { pack_t *ret = NULL; int i; for(i = 0; i < no_packs && ret == NULL; ++i) { if(packs[i] == p) { ret = p; } else { RLOCK(packs[i]); // strcmp, might need to be strcasecmp if doze port if(strcmp(packs[i]->file,file) == 0) ret = packs[i]; RUNLOCK(packs[i]); } } return ret; } int packlist_add(packlist_t *p) { int i,ret = -1; LOCK(global); LOCK(p); for(i = 0; i < global->no_packlists; ++i) { LOCK(global->packlists[i]); if(strcasecmp(global->packlists[i]->name,p->name) == 0 && global->packlists[i]->deleted == 0) { LOGP(L_ERR, "Error, attempted to add duplicate packlist %s", global->packlists[i]->name); UNLOCK(global->packlists[i]); break; } UNLOCK(global->packlists[i]); } if(i == global->no_packlists) { LOGP(L_INF,"Added packlist %s",p->name); PTRARR_ADD(&global->packlists,&global->no_packlists,p); validity_insert(p); se_notify_packlist_add(p); ret = 0; } UNLOCK(global); if(ret == 0) access_verify_entries(p->access); UNLOCK(p); return ret; } void packlist_purge(const time_t now) { packlist_t **old = NULL; int no_old = 0; int i,j,deleted; //D("Packlist Purge Begins"); LOCK(global); for(i = 0, deleted = 0; i < global->no_packlists; ++i) { LOCK(global->packlists[i]); if(IS_PURGE_TIME(global->packlists[i]->deleted,now)) deleted++; UNLOCK(global->packlists[i]); } if(deleted) { old = global->packlists; no_old = global->no_packlists; PTRARR_ALLOC(&(global->packlists),&(global->no_packlists), no_old - deleted); for(i = 0,j = 0; i < no_old; ++i) { LOCK(old[i]); if(!IS_PURGE_TIME(old[i]->deleted,now)) { global->packlists[j++] = old[i]; UNLOCK(old[i]); old[i] = NULL; } else { UNLOCK(old[i]); } } } UNLOCK(global); if(deleted) { for(i = 0; i < no_old; ++i) { if(old[i] != NULL) free_packlist(old[i]); } } if(old != NULL) xfree(old); //D("Packlist Purge Ends"); } int packlist_del(packlist_t *p) { int i; LOCK(global); for(i = 0; i < global->no_users; ++i) { LOCK(global->users[i]); if(global->users[i]->packlists != NULL) PTRARR_DEL(&global->users[i]->packlists, &global->users[i]->no_packlists,p); UNLOCK(global->users[i]); } LOCK(p); if(p->deleted == 0) { LOGP(L_INF,"Deleted packlist %s",p->name); p->deleted = xtime(); validity_delete(p); } UNLOCK(p); UNLOCK(global); return 0; } packlist_t *packlist_find(const char *name) { packlist_t *p = NULL; int i; LOCK(global); for(i = 0; i < global->no_packlists && p == NULL; ++i) { LOCK(global->packlists[i]); if(strcasecmp(global->packlists[i]->name,name) == 0 && global->packlists[i]->deleted == 0) { p = global->packlists[i]; validity_insert(p); } UNLOCK(global->packlists[i]); } UNLOCK(global); return p; } pack_t *pack_clone(pack_t *p) { pack_ref(p); return p; } static int qsort_packcmp_none(const void *a, const void *b) { return 0; } static int qsort_packcmp_az(const void *a, const void *b) { pack_t *ap = *((pack_t **)a), *bp = *((pack_t **)b); return strcmp(ap->label,bp->label); } static int qsort_packcmp_za(const void *a, const void *b) { pack_t *ap = *((pack_t **)a), *bp = *((pack_t **)b); return strcmp(bp->label,ap->label); } static int qsort_packcmp_i_az(const void *a, const void *b) { pack_t *ap = *((pack_t **)a), *bp = *((pack_t **)b); return strcasecmp(ap->label,bp->label); } static int qsort_packcmp_i_za(const void *a, const void *b) { pack_t *ap = *((pack_t **)a), *bp = *((pack_t **)b); return strcasecmp(bp->label,ap->label); } typedef int (*packcmp_func_t)(const void *,const void *); static const packcmp_func_t packcmp[] = { qsort_packcmp_none, /* SORT_NONE = 0 */ qsort_packcmp_az, /* SORT_AZ = 1 */ qsort_packcmp_za, /* SORT_ZA = 2 */ qsort_packcmp_i_az, /* SORT_I_AZ = 3 */ qsort_packcmp_i_za /* SORT_I_ZA = 4 */ }; static void _packlist_sort(packlist_t *l, int type) { int i; for(i = 0; i < l->no_packs; ++i) RLOCK(l->packs[i]); qsort(l->packs,l->no_packs,sizeof(pack_t *),packcmp[type]); for(i = 0; i < l->no_packs; ++i) RUNLOCK(l->packs[i]); } void packlist_sort(packlist_t *l, int type) { LOCK(l); _packlist_sort(l,type); UNLOCK(l); } static int pack_add(packlist_t *l, pack_t *p) { int tmp, req_hash = 0; LOCK(l); tmp = l->no_packs; PTRARR_ADD(&l->packs,&l->no_packs,p); if(l->no_packs == tmp) { // was already in the list UNLOCK(l); return -1; } RLOCK(p); LOGP(L_INF,"Added %s to packlist %s",p->file,l->name); if(p->hashed == 0) req_hash = 1; RUNLOCK(p); if(req_hash) hash_request(p); se_notify_pack_add(0,l,p); if(l->auto_sort != SORT_NONE) _packlist_sort(l,l->auto_sort); UNLOCK(l); return 0; } int pack_add_file(packlist_t *l, const char *file, const char *label, void *evoid, pack_t **ret) { struct stat *edata = (struct stat *)evoid; struct stat sdata; pack_t *p; int i; LOCK(l); if(in_list(l->packs,l->no_packs,NULL,file)) { UNLOCK(l); return -1; } else UNLOCK(l); if(edata == NULL) { i = stat(file,&sdata); if(i != 0) { char errbuf[96]; LOGP(L_ERR,"Failed to stat \"%s\" during pack add (%s)", file, lstrerror_r(errno,errbuf,sizeof(errbuf)) == 0 ? errbuf : "Unknown"); return -1; } edata = &sdata; } if(!S_ISREG(edata->st_mode)) { LOGP(L_ERR,"Failed to add pack \"%s\" (not regular file)",file); return -1; } p = pack_cache_get(global->pack_cache,file,PACK_CACHE_CREATE); WLOCK(p); if(p->size != edata->st_size) { p->size = edata->st_size; if(p->hashed) { p->hashed = 0; xfree(p->md5); xfree(p->crc); p->md5 = NULL; p->crc = NULL; } } if(label != NULL) { xfree(p->label); p->label = xstrdup(label); } WUNLOCK(p); if(pack_add(l,p) == 0) { if(ret != NULL) { pack_ref(p); *ret = p; } return 0; } else { free_pack(p); return -1; } } int pack_del(packlist_t *l, pack_t *p) { int tmp; LOCK(l); tmp = l->no_packs; PTRARR_DEL(&l->packs,&l->no_packs,p); if(tmp == l->no_packs) { UNLOCK(l); return -1; } RLOCK(p); LOGP(L_INF,"Deleted %s from packlist %s",p->file,l->name); RUNLOCK(p); se_notify_pack_del(0,l,p); UNLOCK(l); free_pack(p); return 0; } void packlist_check(packlist_t *l) { struct stat sdata; pqueue_t to_check; pack_t *p; int i,ret; pqueue_init(&to_check,0); LOCK(l); LOGP(L_INF,"Checking packlist %s",l->name); for(i = 0; i < l->no_packs; ++i) { pack_ref(l->packs[i]); pqueue_push_back(&to_check,l->packs[i]); } UNLOCK(l); while((p = pqueue_pop_front(&to_check)) != NULL) { RLOCK(p); ret = stat(p->file,&sdata); if(ret != 0) { // Error so we assume the file is gone RUNLOCK(p); pack_del(l,p); } else { if(!S_ISREG(sdata.st_mode)) { // File no longer regular? RUNLOCK(p); pack_del(l,p); } else if(p->size != sdata.st_size || sdata.st_mtime > p->hashed) { if(p->size != sdata.st_size) LOGP(L_ERR,"File \"%s\" changed size.", p->file); else if(p->hashed != 0) LOGP(L_ERR,"File \"%s\" was modified since last hash, rehashing.", p->file); RUNLOCK(p); WLOCK(p); p->size = sdata.st_size; p->hashed = 0; if(p->md5 != NULL) { xfree(p->md5); p->md5 = NULL; } if(p->crc != NULL) { xfree(p->crc); p->crc = NULL; } WUNLOCK(p); hash_request(p); } else { RUNLOCK(p); } } pack_deref(p); } } static int test_filters(const char *file, char **filters, int no_filters) { char buffer[2048], *to_test; int i,ret; pathtofn(file,buffer,sizeof(buffer)); for(i = 0, ret = 0; i < no_filters && ret == 0; ++i) { if(strchr(filters[i],'/') == NULL) to_test = buffer; else to_test = (char *)file; if(filters[i][0] == '-' && fnmatch(filters[i]+1,to_test,0) == 0) ret = -1; else if(filters[i][0] == '+' && fnmatch(filters[i]+1,to_test,0) == 0) ret = 1; else if(fnmatch(filters[i],to_test,0) == 0) ret = 1; } return ret; } static int qsort_strcmp(const void *a, const void *b) { return strcmp(*((char **)a),*((char **)b)); } static void _scan_dir(packlist_t *l, const char *path, time_t now, pack_t **packs, int no_packs, char **filters, int no_filters, ino_t *history, int depth) { char buffer[2048]; struct dirent *dent; struct stat sdata; DIR *dir; int i, filter; if(stat(path,&sdata) != 0) return; history[depth] = sdata.st_ino; dir = opendir(path); if(dir == NULL) { char errbuf[96]; LOGP(L_ERR,"Failed to open directory \"%s\" (%s)", path,lstrerror_r(errno,errbuf,sizeof(errbuf))); return; } while((dent = readdir(dir)) != NULL) { if(strcmp(dent->d_name,".") == 0 || strcmp(dent->d_name,"..") == 0) continue; snprintf(buffer,sizeof(buffer),"%s%s%s", path, path[strlen(path)-1] != '/' ? "/" : "", dent->d_name); if(stat(buffer,&sdata) != 0) continue; if(filters != NULL) filter = test_filters(buffer,filters,no_filters); else filter = 1; if(S_ISREG(sdata.st_mode) && filter == 1 && !in_list(packs,no_packs,NULL,buffer)) { if(abs(now - sdata.st_mtime) < 5) LOGP(L_INF,"Not adding file \"%s\" (modified in last 5 seconds)",buffer); else pack_add_file(l,buffer,NULL,&sdata,NULL); } else if(S_ISDIR(sdata.st_mode) && depth > 0 && filter >= 0) { for(i = depth; i < MAX_SCAN_DEPTH; ++i) { if(history[i] == sdata.st_ino) break; } if(i != MAX_SCAN_DEPTH) continue; _scan_dir(l,buffer,now,packs,no_packs, filters,no_filters,history,depth-1); } } closedir(dir); } void packlist_scan(packlist_t *l, int scan_depth) { sorttype_t auto_sort; time_t now = xtime(); pack_t **packs = NULL; ino_t history[MAX_SCAN_DEPTH]; char **filters = NULL, **dirs = NULL; int no_packs = 0, no_filters = 0, no_dirs = 0; int i; packlist_check(l); /* The main thing to note here is sorting is disabled during the scan * so as to save overhead on many consecutive pack additions. */ // Copy all required data LOCK(l); LOGP(L_INF,"Scanning packlist %s",l->name); if((auto_sort = l->auto_sort) != SORT_NONE) l->auto_sort = SORT_NONE; if(scan_depth <= 0) scan_depth = l->scan_depth; if(scan_depth < 1) scan_depth = 1; if(scan_depth > MAX_SCAN_DEPTH) scan_depth = MAX_SCAN_DEPTH; packs = PTRARR_DUP(l->packs,l->no_packs,&no_packs); for(i = 0; i < no_packs; ++i) pack_ref(packs[i]); filters = strarr_dup(l->filters,l->no_filters,&no_filters); dirs = strarr_dup(l->dirs,l->no_dirs,&no_dirs); UNLOCK(l); // Do scanning in unlocked state for(i = 0; i < no_dirs; ++i) _scan_dir(l,dirs[i],now,packs,no_packs,filters,no_filters, history,scan_depth-1); // Free Data strarr_free(&dirs,&no_dirs); strarr_free(&filters,&no_filters); for(i = 0; i < no_packs; ++i) pack_deref(packs[i]); if(packs != NULL) xfree(packs); // Update list variables, and sort the new packs if required LOCK(l); l->auto_sort = auto_sort; l->last_scan = now; if(auto_sort != SORT_NONE) _packlist_sort(l,auto_sort); UNLOCK(l); } void packlists_scan(const time_t now) { pqueue_t to_scan; packlist_t *p; int i; pqueue_init(&to_scan,0); LOCK(global); for(i = 0; i < global->no_packlists; ++i) { packlist_t *l = global->packlists[i]; LOCK(l); if(l->deleted == 0 && test_timer(now,l->last_scan,l->dir_scan_interval)) pqueue_push_back(&to_scan,l); UNLOCK(l); } UNLOCK(global); while((p = pqueue_pop_front(&to_scan)) != NULL) packlist_scan(p,-1); } int packlist_check_access(packlist_t *l, network_t *net, const char *host, const char *hostmask, const char *nick) { access_t *access; LOCK(l); if(l->deleted != 0) { // we don't normally check this but here we do UNLOCK(l); return 0; } if(l->access == NULL) { UNLOCK(l); return 1; } access = l->access; UNLOCK(l); return access_check(access,net,host,hostmask,nick); } int packlist_check_access_channel(packlist_t *l, network_t *net, channel_t *chan) { access_t *access; LOCK(l); if(l->deleted != 0) { // we don't normally check this but here we do UNLOCK(l); return 0; } if(l->access == NULL) { UNLOCK(l); return 1; } access = l->access; UNLOCK(l); return access_check_channel(access,net,chan); } long savgspeed(pool_t *p) { double total = 0.0; int i; for(i = 0; i < AVGSPEED; ++i) { total += p->avgspeed[i]; } return (long)(total / (double)AVGSPEED); } /* append xdl head to queue specified by *q */ void packlist_xdl_head(packlist_t *l, pqueue_t *q, colourtype_t colour, const char *prefix, const char *postfix, int addtail) { char buffer[512]; char bqueue[32],bcap[32],bmin[32],bmax[32],btmp1[16],btmp2[16]; char *bold,*unbold; unsigned long long xfer,size; int i; if(colour == COLOUR_IRC) bold = unbold = IRC_BOLD; else if(colour == COLOUR_INT) bold = unbold = COLOUR_BOLD; else bold = unbold = ""; LOCK(l); LOCK(l->queue); LOCK(l->queue->pool); if(l->queue->no_qsends > 0) snprintf(bqueue,sizeof(bqueue), "Queue: %d/%d, ", l->queue->no_qsends, l->queue->length); else strcpy(bqueue,""); if(l->queue->pool->bandwidth != 0) snprintf(bcap,sizeof(bcap), "Cap: %ldKiB/sec, ", (long)l->queue->pool->bandwidth); else strcpy(bcap,""); if(l->queue->pool->send_min_bandwidth != 0) snprintf(bmin,sizeof(bmin), "Min: %ldKiB/sec, ", (long)l->queue->pool->send_min_bandwidth); else strcpy(bmin,""); if(l->queue->pool->send_max_bandwidth != 0) snprintf(bmax,sizeof(bmax), "Max: %ldKiB/sec, ", (long)l->queue->pool->send_max_bandwidth); else strcpy(bmax,""); snprintf(buffer,sizeof(buffer), "%s%s**%s %d packs %s**%s %d of %d slots open, %s%s%sRecord: %ldKiB/s %s**%s%s", prefix, bold,unbold,l->no_packs,bold,unbold, l->queue->pool->sends - l->queue->pool->no_csends > 0 ? l->queue->pool->sends - l->queue->pool->no_csends : 0, l->queue->pool->sends, bqueue,bmin,bmax, (long)(l->queue->pool->record_send / 1024L), bold,unbold, postfix ); pqueue_push_back(q,xstrdup(buffer)); snprintf(buffer,sizeof(buffer), "%s%s**%s Bandwidth Usage %s**%s Current: %ldKiB/s, %sRecord: %ldKiB/s %s**%s%s", prefix, bold,unbold,bold,unbold, (long)(savgspeed(l->queue->pool) / 1024L), bcap, (long)(l->queue->pool->record_rate / 1024L), bold,unbold, postfix ); pqueue_push_back(q,xstrdup(buffer)); xfer = ((unsigned long long)l->queue->pool->stat_mib)*(1024*1024) + (unsigned long long)l->queue->pool->stat_carry; UNLOCK(l->queue->pool); UNLOCK(l->queue); for(i = 0, size = 0; i < l->no_packs; ++i) { RLOCK(l->packs[i]); size += (unsigned long long) l->packs[i]->size; RUNLOCK(l->packs[i]); } snprintf(buffer,sizeof(buffer), "%s%s**%s Total Offered: %s, Total Transferred: %s %s**%s%s", prefix,bold,unbold, format_bytes(btmp1,sizeof(btmp1),size,1), format_bytes(btmp2,sizeof(btmp2),xfer,1), bold,unbold,postfix); pqueue_push_back(q,xstrdup(buffer)); if(addtail) { snprintf(buffer,sizeof(buffer), "%s%s**%s To request a file type: \"/msg $BOT xdcc send %s #x\" %s**%s%s", prefix,bold,unbold,l->name,bold,unbold,postfix ); pqueue_push_back(q,xstrdup(buffer)); } UNLOCK(l); } void packlist_xdl_body(packlist_t *l, pqueue_t *q, colourtype_t colour, const char *prefix, const char *postfix) { char buffer1[512],buffer2[512],buffer3[16]; char *ptr; size_t len; int i,pos; LOCK(l); for(i = 0; i < l->no_packs; ++i) { RLOCK(l->packs[i]); pos = IMIN( snprintf(buffer1,sizeof(buffer1), "%s%%9#%-3d%%9 %3dx [%s] %s", prefix,i+1, l->packs[i]->no_gets, three_digit_size(buffer3,l->packs[i]->size), l->packs[i]->label), sizeof(buffer1)-1 ); if(l->packs[i]->hashed && l->hash_display != HASH_NONE) { if(l->hash_display == HASH_CRC) { snprintf(buffer1+pos,sizeof(buffer1)-pos, " [CRC:%8s]%s", l->packs[i]->crc, postfix ); } else if(l->hash_display == HASH_MD5) { snprintf(buffer1+pos,sizeof(buffer1)-pos, " [MD5:%32s]%s", l->packs[i]->md5, postfix ); } else { snprintf(buffer1+pos,sizeof(buffer1)-pos, " [CRC:%8s] [MD5:%32s]%s", l->packs[i]->crc,l->packs[i]->md5, postfix ); } } else { snprintf(buffer1+pos,sizeof(buffer1)-pos,"%s",postfix); } RUNLOCK(l->packs[i]); len = colourise(colour,buffer2,sizeof(buffer2),buffer1); ptr = xalloc(len+1); memcpy(ptr,buffer2,len+1); pqueue_push_back(q,ptr); } UNLOCK(l); } static int do_taglines(pqueue_t *q, colourtype_t colour, const char *name, char **lines, int no_lines, const char *prefix, const char *postfix) { char buffer1[512]; char buffer2[512]; int i,pos; if(lines == NULL || no_lines <= 0) return 0; for(i = 0; i < no_lines; ++i) { pos = snprintf(buffer1,sizeof(buffer1), "%s%s**%s ",prefix,COLOUR_BOLD,COLOUR_BOLD); pos += xstrncpy_rpl(buffer1+pos,lines[i], sizeof(buffer1)-pos, "$LIST",name); snprintf(buffer1+pos,sizeof(buffer1)-pos, " %s%s**%s%s", COLOUR_OFF,COLOUR_BOLD,COLOUR_BOLD,postfix); colourise(colour,buffer2,sizeof(buffer2),buffer1); pqueue_push_back(q,xstrdup(buffer2)); } return 1; } void packlist_xdl_tail(packlist_t *l, pqueue_t *q, colourtype_t colour, network_t *net, channel_t *chan, const char *prefix, const char *postfix) { char name[128]; int done = 0; LOCK(l); xstrncpy(name,l->name,sizeof(name)); UNLOCK(l); if(chan != NULL) { LOCK(chan); done = do_taglines(q,colour,name, chan->taglines,chan->no_taglines, prefix,postfix); UNLOCK(chan); } if(!done && l != NULL) { LOCK(l); done = do_taglines(q,colour,name, l->taglines,l->no_taglines, prefix,postfix); UNLOCK(l); } if(!done && net != NULL) { LOCK(net); done = do_taglines(q,colour,name, net->settings->taglines, net->settings->no_taglines, prefix,postfix); UNLOCK(net); } if(!done) { LOCK(global); done = do_taglines(q,colour,name, global->network_settings->taglines, global->network_settings->no_taglines, prefix,postfix); UNLOCK(global); } } int pack_ref(pack_t *p) { int ret; WLOCK(p); ret = ++p->ref_count; WUNLOCK(p); return ret; } int pack_deref(pack_t *p) { int ret; if(pack_cache_present(global->pack_cache,p)) { ret = pack_cache_deref(global->pack_cache,p); } else { WLOCK(p); ret = --p->ref_count; WUNLOCK(p); } if(ret == 0) free_pack_real(p); return ret; } int packlist_valid(packlist_t *l) { int i; if(l == NULL) return 0; if(validity_test(l)) return 1; LOCK(global); for(i = 0; i < global->no_packlists; ++i) { if(global->packlists[i] == l) { LOCK(l); i = l->deleted; if(l->deleted == 0) validity_insert(l); UNLOCK(l); UNLOCK(global); if(i == 0) // l->deleted == 0 return 1; else return 0; } } UNLOCK(global); return 0; } int pack_valid(packlist_t *l, pack_t *p) { if(l == NULL || p == NULL) return 0; if(packlist_valid(l)) { int i; LOCK(l); for(i = 0; i < l->no_packs; ++i) if(l->packs[i] == p) { pack_ref(p); UNLOCK(l); return 1; } UNLOCK(l); } return 0; } int packlist_rename(packlist_t *l, const char *name) { int i,ret = 0; if(l == NULL || name == NULL) return -1; LOCK(global); for(i = 0; i < global->no_packlists && ret == 0; ++i) { LOCK(global->packlists[i]); if(global->packlists[i]->deleted == 0 && strcasecmp(global->packlists[i]->name,name) == 0) ret = -1; UNLOCK(global->packlists[i]); } if(ret == 0) { LOCK(l); if(l->name != NULL) xfree(l->name); l->name = xstrdup(name); UNLOCK(l); } UNLOCK(global); return ret; } void packlist_plist_generate(packlist_t *l, pqueue_t *pq, pformat_t pformat, colourtype_t colour_type, network_t *net, channel_t *chan, const char *prefix, const char *postfix) { char buffer[512]; switch (pformat) { case PFORMAT_MINIMAL: LOCK(l); snprintf(buffer,sizeof(buffer), "%s**%s XDCC %s**%s Packlist: %s\r\n", IRC_BOLD,IRC_BOLD, IRC_BOLD,IRC_BOLD, l->name); UNLOCK(l); pqueue_push_back(pq,xstrdup(buffer)); packlist_xdl_body(l,pq,colour_type,prefix,postfix); break; case PFORMAT_SUMMARY: packlist_xdl_head(l,pq,colour_type,prefix,postfix,0); LOCK(l); snprintf(buffer,sizeof(buffer), "%s**%s For a Listing: \"/msg $BOT XDCC LIST %s\" %s**%s", IRC_BOLD,IRC_BOLD, l->name, IRC_BOLD,IRC_BOLD); UNLOCK(l); pqueue_push_back(pq,xstrdup(buffer)); packlist_xdl_tail(l,pq,colour_type,net,chan, prefix,postfix); break; case PFORMAT_FULL: packlist_xdl_head(l,pq,colour_type,prefix,postfix,1); packlist_xdl_body(l,pq,colour_type,prefix,postfix); packlist_xdl_tail(l,pq,colour_type,net,chan, prefix,postfix); break; case PFORMAT_TAGONLY: packlist_xdl_tail(l,pq,colour_type,net,chan, prefix,postfix); break; } } void packlist_xdl_generate(packlist_t *l, pqueue_t *pq, listtype_t type, colourtype_t colour_type, network_t *net, channel_t *chan, const char *prefix, const char *postfix) { if(type == LIST_CHAT) return; if(type == LIST_NORMAL) packlist_xdl_head(l,pq,colour_type,prefix,postfix,1); else if(type == LIST_NOPACKS) packlist_xdl_head(l,pq,colour_type,prefix,postfix,0); if(type == LIST_NORMAL) packlist_xdl_body(l,pq,colour_type,prefix,postfix); packlist_xdl_tail(l,pq,colour_type,net,chan,prefix,postfix); } /** Settings Data **/ static setting_t packlist_data[] = { {"auto-sort", ST_ENUM,OFFSETOF(packlist_t,auto_sort), 0,NULL,NULL,sorttype_to_str,str_to_sorttype}, {"command-limit", ST_INT, OFFSETOF(packlist_t,command_limit), 0,"0",NULL,NULL,NULL}, {"dir-scan-interval", ST_UINT,OFFSETOF(packlist_t,dir_scan_interval), 0,"0",NULL,NULL,NULL}, {"hash-display", ST_ENUM,OFFSETOF(packlist_t,hash_display), 0,NULL,NULL,hashtype_to_str,str_to_hashtype}, {"response", ST_ENUM,OFFSETOF(packlist_t,response), 0,NULL,NULL,responsetype_to_str,str_to_responsetype}, {"retries", ST_INT, OFFSETOF(packlist_t,retries), 0,"0",NULL,NULL,NULL}, {"scan-depth", ST_INT,OFFSETOF(packlist_t,scan_depth), 0,"1",MAX_SCAN_DEPTH_STR,NULL,NULL}, {"time-limit", ST_INT, OFFSETOF(packlist_t,time_limit), 0,"0",NULL,NULL,NULL}, {"type", ST_ENUM,OFFSETOF(packlist_t,type), 0,NULL,NULL,listtype_to_str,str_to_listtype}, {NULL} }; int packlist_apply_setting(packlist_t *p, const char *name, const char *value) { value_t *v = value_string(name,value); int ret; LOCK(p); ret = apply_setting(packlist_data,p,v); UNLOCK(p); xfree(v); return ret; } int packlist_read_settings(packlist_t *p, pqueue_t *out) { int ret; LOCK(p); ret = read_settings(packlist_data,p,out); UNLOCK(p); return ret; }