Logo Search packages:      
Sourcecode: tucnak2 version File versions  Download package

cwdb.c

/*
    Tucnak - VHF contest log
    Copyright (C) 2002-2006  Ladislav Vaiz <ok1zia@nagano.cz>

    This program is free software; you can redistribute it and/or                                                        
    modify it under the terms of the GNU General Public License                                                          
    version 2 as published by the Free Software Foundation.

*/

#include "header.h"

#include <string.h>
struct cw *cw;
static gchar *cw_next;
static gchar *wc_next;

struct cw *init_cw(){
    struct cw *cw;
    time_t now;
    struct tm tm;

    cw = g_new0(struct cw, 1);
    
    cw->cw = t_hash_table_new(g_str_hash, g_str_equal);
    cw->wc = g_hash_table_new(g_str_hash, g_str_equal);
    
    cw_next = NULL;
    wc_next = NULL;
    cw->latest = 0;
    
    
    time(&now);
    now -= 740 * 86400L; /* 740 days = two years + something */
    gmtime_r(&now, &tm);
    cw->minstamp = (tm.tm_year+1900)*10000 + (tm.tm_mon+1)*100 + tm.tm_mday;

    return cw;
}

gboolean free_cw_item(gpointer key, gpointer value, gpointer user_data){
    struct cw_item *cwi;
    
    g_free(key);
    cwi = (struct cw_item *)value;
    if (cwi->wwl0) g_free(cwi->wwl0);
    if (cwi->wwl1) g_free(cwi->wwl1);
    g_free(value);
    return 0;    
}

gboolean free_wc_item(gpointer key, gpointer value, gpointer user_data){
    struct wc_item *wci;
    
    g_free(key);
    wci = (struct wc_item *)value;
    if (wci->call0) g_free(wci->call0);
    if (wci->call1) g_free(wci->call1);
    g_free(value);
    return 0;
        
}

void free_cw(struct cw *cw){
    g_hash_table_foreach_remove(cw->wc, free_wc_item, NULL);
    g_hash_table_destroy(cw->wc);
    
    t_hash_table_foreach_remove(cw->cw, free_cw_item, NULL);
    t_hash_table_destroy(cw->cw);
    g_free(cw);
}

gint get_cw_size(struct cw *cw){
    return t_hash_table_size(cw->cw);
}

gint get_wc_size(struct cw *cw){
    return g_hash_table_size(cw->wc);
}

#define CW_DELIM " \t\r\n"

void load_one_cw(struct cw *cw, gchar *s){
    gchar *call, *wwl, *stamp_str, *qrv_str;
    char *token_ptr;
    
    uc(s);
    call = strtok_r(s, CW_DELIM, &token_ptr);
    if (!call) return;

    wwl = strtok_r(NULL, CW_DELIM, &token_ptr);
    if (!wwl) return;

    stamp_str = strtok_r(NULL, CW_DELIM, &token_ptr);
    if (!stamp_str) return;
    
    qrv_str = strtok_r(NULL, CW_DELIM, &token_ptr);
    /*dbg("qrv_str(%s)=%s\n", call, qrv_str);*/

    add_cw(cw, call, wwl, atoi(stamp_str), qrv_str); /* qrv can be null */
    add_wc(cw, wwl, call, atoi(stamp_str));
}

int load_cw_from_file(struct cw *cw, gchar *filename){
    FILE *f;
    char s[102];

    f = fopen(filename, "rt");
    if (!f){
        /*dbg("Can't open '%s'\n", filename);*/
        return -1;
    }

    while((fgets(s, 100, f))!=NULL){
        load_one_cw(cw,s);
    }

    fclose(f);
    return 0;
}


void read_cw_files(struct cw *cw){
    gchar *s;
    
    load_cw_from_file(cw, "/etc/tucnakcw");
    s = g_strconcat(getenv("HOME"), "/tucnak/tucnakcw", NULL); 
    load_cw_from_file(cw, s);
    g_free(s);
}

void save_one_cw(gpointer key, gpointer value, gpointer user_data){
    GString *gs;
    gchar *call;
    struct cw_item *cwi;
    gchar qrv_str[33], *c;
    int i;

    gs   = (GString *) user_data;
    call = (gchar *) key;
    cwi  = (struct cw_item *) value;
    
    for (i=0, c=qrv_str;i<32;i++){
        if (!(cwi->qrv & (1<<i))) continue;
        *c='A'+i;
        c++;
    }
    *c='\0';

    if (cwi->wwl0) 
        g_string_sprintfa(gs, "%-14s %-6s %08d %s\n", call, cwi->wwl0, cwi->stamp0, qrv_str);
    
    if (cwi->wwl1) 
        g_string_sprintfa(gs, "%-14s %-6s %08d %s\n", call, cwi->wwl1, cwi->stamp1, qrv_str);
    
}

int save_cw_string(struct cw *cw, GString *gs){
    t_hash_table_foreach(cw->cw, save_one_cw, (gpointer) gs);
    return 0;
}

int save_cw_into_file(struct cw *cw, gchar *filename){
    FILE *f;
    GString *gs;
    int ret;

    f = fopen(filename, "wt"); /* FIXME swp first */
    if (!f) {
        return errno;
    }
    
    gs=g_string_sized_new(100000);
    save_cw_string(cw,gs);
    ret = fprintf(f,"%s",gs->str) != gs->len ? errno: 0;
    fclose(f);
    g_string_free(gs,TRUE);
    return ret;
}


void add_cw(struct cw *cw, gchar *call, gchar *wwl, gint stamp, gchar *qrv_str){
    struct cw_item *cwi;
    char *c;
    
    if (stamp<0) return; 
    if (stamp>cw->latest) cw->latest=stamp;
    
    cwi = t_hash_table_lookup(cw->cw, call);
    if (!cwi){
        cwi = g_new0(struct cw_item, 1);
        t_hash_table_insert(cw->cw, g_strdup(call), cwi);
    }
    
    if (qrv_str){ /* can be NULL*/
        for (c=qrv_str;*c!='\0';c++){
            *c=upcase(*c);
            cwi->qrv|=1<<(*c-'A');
        }
    }
    
    if (stamp < cwi->stamp1) return;
                
    if (stamp < cwi->stamp0){
        if (strcasecmp(cwi->wwl0, wwl)==0) return;

        if (cwi->wwl1) g_free(cwi->wwl1);
        cwi->wwl1   = g_strdup(wwl);
        cwi->stamp1 = stamp;
        return;
    }

    if (cwi->wwl0 && strcasecmp(cwi->wwl0, wwl)==0) {
        cwi->stamp0 = stamp;
        return;
    }

    if (cwi->wwl1) g_free(cwi->wwl1);
    cwi->wwl1   = cwi->wwl0;
    cwi->stamp1 = cwi->stamp0;
    
    cwi->wwl0   = g_strdup(wwl);
    cwi->stamp0 = stamp;
}


void add_wc(struct cw *cw, gchar *wwl, gchar *call, gint stamp){
    struct wc_item *wci;
    
    if (stamp<0) return; 
    if (stamp>cw->latest) cw->latest=stamp;
    
    wci = g_hash_table_lookup(cw->wc, wwl);
    if (!wci){
        wci = g_new0(struct wc_item, 1);
        g_hash_table_insert(cw->wc, g_strdup(wwl), wci);
    }

    if (stamp < wci->stamp1) return;

    if (stamp < wci->stamp0){
        if (strcasecmp(wci->call0, call)==0) return;

        if (wci->call1) g_free(wci->call1);
        wci->call1  = g_strdup(call);
        wci->stamp1 = stamp;
        return;
    }

    if (wci->call0 && strcasecmp(wci->call0, call)==0) {
        wci->stamp0 = stamp;
        return;
    }
    
    
    if (wci->call1) g_free(wci->call1);
    wci->call1  = wci->call0;
    wci->stamp1 = wci->stamp0;
    
    wci->call0  = g_strdup(call);
    wci->stamp0 = stamp;
}


gchar *find_wwl_by_call(struct cw *cw, gchar *call){
    struct cw_item *cwi;

    if (!call) return cw_next;
    cw_next = NULL;
        
    cwi = t_hash_table_lookup(cw->cw, call);
    if (!cwi) return NULL;
    
    cw_next = cwi->wwl1;
    return cwi->wwl0;
}

gchar *find_wwl_by_call_newer(struct cw *cw, gchar *call, int maxstamp){
    struct cw_item *cwi;

    cwi = t_hash_table_lookup(cw->cw, call);
    if (!cwi) return NULL;
    if (cwi->stamp0 > maxstamp) return cwi->wwl0;
    if (cwi->stamp1 > maxstamp) return cwi->wwl1;
    return NULL;
}

gchar *find_call_by_wwl(struct cw *cw, gchar *wwl){
    struct wc_item *wci;

    if (!wwl) return wc_next;
    wc_next = NULL;
        
    wci = g_hash_table_lookup(cw->wc, wwl);
    if (!wci) return NULL;
    
    wc_next = wci->call1;
    return wci->call0;
}


gchar *find_qrv_str_by_call(struct cw *cw, gchar *call){
    int i;
    gchar *c;
    struct cw_item *cwi;
    gint qrv;
    static gchar qrv_str[33];
    gchar *ret;
    char s[25];
    
    if (!aband) return NULL;

    qrv=0;
    
    cwi = t_hash_table_lookup(cw->cw, call);
    if (cwi) qrv|=cwi->qrv;

    cwi = t_hash_table_lookup(cw->cw, get_raw_call(s, call));
    if (cwi) qrv|=cwi->qrv;

    c=g_strdup_printf("%s/P", s);
    cwi = t_hash_table_lookup(cw->cw, c);
    if (cwi) qrv|=cwi->qrv;
    g_free(c);

    if (!qrv) return NULL;
    
    for (i=toupper(aband->bandchar)+1,c=qrv_str;
         i<='Z';
         i++){
        
        if (!(qrv & ctest->qrv & (1<<(i-'A')))) continue;
        
        *c=i;
        c++;
    }
    *c='\0';
    ret=strlen(qrv_str)?qrv_str:NULL;
    /*log_addf("find_qrv_str_by_call(%s)='%s'", call, ret);*/
    return ret;
}

int is_string_in_array(GPtrArray *arr, gchar *str){
    int i;
    gchar *c;

    for (i=0; i<arr->len; i++){
        c = (gchar *)g_ptr_array_index(arr, i);
        if (!c) continue;

        if (strcmp(c, str)==0) return 1;
        
    }
    return 0;
}


int cmp_cw_qs(gchar *call, struct cw_item *cwi, GPtrArray *result){
    gchar *c;
    int ret=0, i;
    int qrb_int, qtf_int;
    char qrv_str[35];
    int qrvfilter;

    qrvfilter = ctest ? ctest->qrv : -1; 
    
    c=qrv_str;
    for (i=0;i<32;i++){
        if ((cwi->qrv & qrvfilter & (1<<i)) == 0) continue;
        *c='A'+i;
        c++;
    }
    *c='\0';

    
    if (my_strstr(call, gses->qs_str)){
        if (cwi->wwl0) {
            qrb_qtf_int(cwi->wwl0, &qrb_int, &qtf_int);
            c=g_strdup_printf("%-10s %-6s%5d/%3d %s", call, cwi->wwl0, qrb_int, qtf_int, qrv_str);
            g_ptr_array_add(result, c);
            if (cwi->wwl1){ /* wwl1 is only together with wwl0 */
                qrb_qtf_int(cwi->wwl1, &qrb_int, &qtf_int);
                c=g_strdup_printf("%-10s %-6s%5d/%3d %s", call, cwi->wwl1, qrb_int, qtf_int, qrv_str);
                g_ptr_array_add(result, c);
            }
        }else{
            c=g_strdup(call);
            g_ptr_array_add(result, c);
        }
        goto x;
    }
    
    if (cwi->wwl0 && my_strstr(cwi->wwl0, gses->qs_str)){
        qrb_qtf_int(cwi->wwl0, &qrb_int, &qtf_int);
        c=g_strdup_printf("%-10s %-6s%5d/%3d %s", call, cwi->wwl0, qrb_int, qtf_int, qrv_str);
     /*   dbg(",%s", c);*/
        g_ptr_array_add(result, c);
        goto x;
    }
    
    if (cwi->wwl1 && my_strstr(cwi->wwl1, gses->qs_str)){
        qrb_qtf_int(cwi->wwl1, &qrb_int, &qtf_int);
        c=g_strdup_printf("%-10s %-6s%5d/%3d %s", call, cwi->wwl1, qrb_int, qtf_int, qrv_str);
    /*    dbg(",%s", c);  */
        g_ptr_array_add(result, c);
        goto x;
    }
x:;    
    return ret;
}

int compare_gstring(const void *a, const void *b){
    gchar **sa, **sb;

    sa = (gchar **)a;
    sb = (gchar **)b;

    return (strcmp(*sa, *sb));
}

void get_cw_qs(gchar *str){
    
    qs_thread_kill();
    
    
    if (strlen(str)<2) {
        g_ptr_array_free_items(gses->qs);
        return;
    }

    CONDGFREE(gses->qs_str);
    gses->qs_str=g_strdup(str);
    gses->qs_max_matches = term->y - QSONR_HEIGHT - 4 - cfg->loglines - 1;
    if (aband) gses->qs_max_matches -= aband->spypeers->len;
    if (ctest && ctest->bands->len==1) gses->qs_max_matches*=2;
    if (!ctest) gses->qs_max_matches*=3;
    qs_thread_create();
}

gpointer qs_thread_func(gpointer data){
    char s[256];
    GPtrArray *result;
    THashNode *node;
    gint i;
    int count;   

    result=g_ptr_array_new();
    
    count=0;
    for (i = 0; i < cw->cw->size; i++){
        for (node = cw->cw->nodes[i]; node; node = node->next){
            cmp_cw_qs(node->key, node->value, result);
            
            if (result->len >= gses->qs_max_matches) goto x;
   
            if (gses->qs_thread_break){
                g_ptr_array_free_all(result);
                return NULL;
            }

        }
    }
x:; 
    g_index_array_qsort((GIndexArray *)result, compare_gstring); 
    
    LOCK(gses->qs);
    g_ptr_array_free_all(gses->qs);
    gses->qs=result;
    UNLOCK(gses->qs);
    
    sprintf(s, "CWQS\n");
    write(tpipe->threadpipe_write, s, strlen(s));

      return NULL;
}

void qs_thread_create(){
    if (gses->qs_thread) raise(SIGSEGV);
    gses->qs_thread_break=0;
    gses->qs_thread=g_thread_create(qs_thread_func, (gpointer)NULL, TRUE, NULL);
    if (!gses->qs_thread) raise(SIGSEGV);
}


void qs_thread_join(){
    if (!gses->qs_thread) return;
    g_thread_join(gses->qs_thread);
    gses->qs_thread=NULL;
}

void qs_thread_kill(){
    if (!gses->qs_thread) return;
    gses->qs_thread_break=1;
    g_thread_join(gses->qs_thread);
  /*  dbg("done\n");*/
    gses->qs_thread=NULL;
}

void update_cw_from_band(struct cw *cw, struct band *band){
    int i;
    struct qso *q;
    gchar qrv_str[2];

    stats_thread_join(band);
    qrv_str[0]=band->bandchar;
    qrv_str[1]='\0';

    for (i=0; i<band->qsos->len; i++){
        q = (struct qso *)g_ptr_array_index(band->qsos, i);

        if (q->error) continue;
        
        if (!q->callsign || !q->locator || !q->date_str) continue;
        if (strlen(q->locator)!=6) continue;

        add_cw(cw, q->callsign, q->locator, atoi(q->date_str), qrv_str);
        add_wc(cw, q->locator, q->callsign, atoi(q->date_str));
        
    }
    
}


void update_cw_from_ctest(struct cw *cw, struct contest *ctest){
    int i;
    struct band *band;

    if (!ctest) return;

    for (i=0; i<ctest->bands->len; i++){
        band = (struct band *) g_ptr_array_index(ctest->bands, i);

        update_cw_from_band(cw, band);
    }
    
}



int similar_calls(const char *call1, const char *call2, int factor, int thr, int p){
    const char *c1, *c2;
    int f1, f2, f3;

    if (factor>thr) return 9;
    c1=call1;
    c2=call2;

    while(*c1!='\0' && *c2!='\0'){

        if (*c1==*c2){
            c1++;
            c2++;
            continue;
        }
        f1 = similar_calls(c1+1, c2+1, factor+1, thr, 0); 
        f2 = similar_calls(c1, c2+1, factor+2, thr, 0);
        f3 = similar_calls(c1+1, c2, factor+2, thr, 0);
        if (f1<f2){
            if (f1<f3){
                factor=f1;
            }else{
                if (f2<f3) factor=f2;
                else factor=f3;
            }
        }else{
            if (f2<f3) factor=f2;
            else factor=f3;
        }
        break;

    }

    if (p) printf("similar %s %s = %d\n", call1, call2, factor);
    /*else printf("          %s %s = %d\n", call1, call2, factor);*/
    return factor;
}


int get_susp_ambiguous_call(struct cw *cw, char *call, char *wwl, GString *gs, int thr){
    int i;
    THashNode *node;
    struct cw_item *cwi;

    for (i = 0; i < cw->cw->size; i++){
        for (node = cw->cw->nodes[i]; node; node = node->next){
            cwi  = (struct cw_item *) node->value;
            
            if ((cwi->wwl0 && strcmp(cwi->wwl0, wwl)==0 && cwi->stamp0 > cw->minstamp) ||
                (cwi->wwl1 && strcmp(cwi->wwl1, wwl)==0 && cwi->stamp1 > cw->minstamp)){
                            
                /* dbg("hit %s %s\n", node->key, wwl);*/
                if (strcmp((gchar*)node->key, call)==0) continue;
                if (similar_calls((gchar*)node->key, call, 0, thr, 0)<=thr){
                    if (!gs) return 1;

                    g_string_append(gs, node->key);
                    g_string_append_c(gs, ' ');
                }
            }
        }
    }
    return 0;
}

int cwdb_call_info(GString *gs, gchar *call, gchar *stroke){
    struct cw_item *cwi;
    char c[40];

    strcpy(c, call);
    strcat(c, stroke);
    cwi = t_hash_table_lookup(cw->cw, c);
    if (!cwi) return 0;
    if (!cwi->wwl0) return 0;  /* wwl0 should be always defined */
    g_string_sprintfa(gs, "C_W: %-9s %s %d", c, cwi->wwl0, cwi->stamp0);
    if (cwi->wwl1) g_string_sprintfa(gs, ", %s %d", cwi->wwl1, cwi->stamp1);
    g_string_append(gs, "\n");
    return 1;
}

Generated by  Doxygen 1.6.0   Back to index