/*
    Tucnak - VHF contest log
    Copyright (C) 2002-2022  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 "bfu.h"
#include "chart.h"
#include "control.h"
#include "cwdb.h"
#include "edi.h"
#include "excdb.h"
#include "fifo.h"
#include "main.h"
#include "menu.h"
#include "map.h"
#include "namedb.h"
#include "net.h"
#include "oct8tor.h"
#include "qrvdb.h"
#include "qsodb.h"
#include "rotar.h"
#include "rain.h"
#include "session.h"
#include "sked.h"
#include "stats.h"
#include "tregex.h"
#include "tsdl.h"

static int edi_serid_used;

#define dumpvar(var) { int dvi; dbg("%s=",#var); for (dvi=0; dvi<sizeof(var); dvi++) dbg("%02x ", ((char *)&var)[dvi]); dbg("\n");}

void add_qso_str1(GString *gs, struct qso *q, struct band *b){
    char s[1024];

    if (q->date_str && strlen(q->date_str)>2){
        safe_strncpy0(s, q->date_str+2, 7); 
        g_string_append(gs, s);
    }
    g_string_append_c(gs, ';');
   
    g_string_append(gs, safe_strncpy0(s, q->time_str, 5));
    g_string_append_c(gs, ';');
    
    if (q->error)
        g_string_append(gs, "ERROR");
    else
        g_string_append(gs, z_str_uc(safe_strncpy0(s, q->callsign, 20)));
    g_string_append_c(gs, ';');
   
    g_string_append_printf(gs, "%d", q->mode);
    g_string_append_c(gs, ';');
    
    g_string_append(gs, z_str_uc(safe_strncpy0(s, q->rsts, 6)));
    g_string_append_c(gs, ';');
   
    g_string_append(gs, z_str_uc(safe_strncpy0(s, q->qsonrs, 5)));
    g_string_append_c(gs, ';');
   
    g_string_append(gs, z_str_uc(safe_strncpy0(s, q->rstr, 6)));
    g_string_append_c(gs, ';');
   
    g_string_append(gs, z_str_uc(safe_strncpy0(s, q->qsonrr, 5)));
    g_string_append_c(gs, ';');
   
	safe_strncpy0(s, q->exc, MAX_EXC_LEN+1);
    g_string_append(gs, z_str_uc(s));
    g_string_append_c(gs, ';');
    
    g_string_append(gs, z_str_uc(safe_strncpy0(s, q->locator, 7)));
    g_string_append_c(gs, ';');
}
    
void add_qso_str2(GString *gs, struct qso *q, struct band *b){
    
    if (!q->dupe && !q->error && strcasecmp(q->callsign, "ERROR")!=0)
        g_string_append_printf(gs, "%d;", q->qsop/* * b->bandmulti*/);
    else{
        g_string_append(gs, "0;");
        dump_qso(q, "write_edi_qsos");
    }
    
    if (q->new_ & NEW_EXC) g_string_append_c(gs, 'N');
    g_string_append_c(gs, ';');
    
    if (q->new_ & NEW_WWL) g_string_append_c(gs, 'N');
    g_string_append_c(gs, ';');
    
    if (q->new_ & NEW_DXC) g_string_append_c(gs, 'N');
    g_string_append_c(gs, ';');
    
    if (q->dupe) g_string_append_c(gs, 'D');
}

void add_qso_str3(GString *gs, struct qso *q, struct band *b){
    char s[1024];

    g_string_append(gs, q->source);
    g_string_append_c(gs, ';');
    
    g_string_append(gs, fixsemi(q->operator_));
    g_string_append_c(gs, ';');
    
    g_string_append_printf(gs, "%d;", (int)q->stamp);
   
    if (q->error) g_string_append(gs, q->callsign);
    g_string_append_c(gs, ';');
    
    safe_strncpy0(s, q->date_str, 3);
    g_string_append(gs, s);
    g_string_append_c(gs, ';');
    
    safe_strncpy0(s, q->remark, MAX_STR_LEN);
    g_string_append(gs, fixsemi(s));
    
    g_string_append_printf(gs, ";%d", q->ser_id);
    
    g_string_append_printf(gs, ";%1.0f", q->qrg);

	g_string_append_printf(gs, ";%d", q->phase);
}


const char *get_psect_str(struct band *b){
	switch(b->psect){
		case 0:
			return "Multi";
		case 1:
			return "Single";
		case 2:
			return "Check";
		default:
			return b->opsect;
	}
}



static int write_edi_header(struct band *b, struct config_band *confb, FILE *f){
    char s[1024];
    GString *gs;
    int ret;
	int qsomult;
    
    gs = g_string_sized_new(1024);
    g_string_append_printf(gs, "[REG1TEST;1]\r\n");
    g_string_append_printf(gs, "TName=%s\r\n", safe_strncpy0(s, ctest->tname, 69));
    if (!b->qsos->len)
        g_string_append_printf(gs, "TDate=%s;%s\r\n", ctest->cdate, ctest->cdate); 
    else
        g_string_append_printf(gs, "TDate=%d;%d\r\n", b->stats->first_date, b->stats->last_date); 
    g_string_append_printf(gs, "PCall=%s\r\n", z_str_uc(safe_strncpy0(s, ctest->pcall, 69)));
    g_string_append_printf(gs, "PWWLo=%s\r\n", z_str_uc(safe_strncpy0(s, ctest->pwwlo, 69)));
	g_string_append_printf(gs, "PExch=%s\r\n", z_str_uc(safe_strncpy0(s, ctest->pexch, MAX_EXC_LEN+1)));
    g_string_append_printf(gs, "PAdr1=%s\r\n",    safe_strncpy0(s, ctest->padr1, 69));
    g_string_append_printf(gs, "PAdr2=%s\r\n",    safe_strncpy0(s, ctest->padr2, 69));
	g_string_append_printf(gs, "PSect=%s\r\n", get_psect_str(b));
    g_string_append_printf(gs, "PBand=%s\r\n", b->pband);
    g_string_append_printf(gs, "PClub=%s\r\n", z_str_uc(safe_strncpy0(s, ctest->pclub, 69)));
    g_string_append_printf(gs, "RName=%s\r\n",    safe_strncpy0(s, ctest->rname, 69));
    g_string_append_printf(gs, "RCall=%s\r\n", z_str_uc(safe_strncpy0(s, ctest->rcall, 69)));
    g_string_append_printf(gs, "RAdr1=%s\r\n",    safe_strncpy0(s, ctest->radr1, 69));
    g_string_append_printf(gs, "RAdr2=%s\r\n",    safe_strncpy0(s, ctest->radr2, 69));
    g_string_append_printf(gs, "RPoCo=%s\r\n",    safe_strncpy0(s, ctest->rpoco, 69));
    g_string_append_printf(gs, "RCity=%s\r\n",    safe_strncpy0(s, ctest->rcity, 69));
    g_string_append_printf(gs, "RCoun=%s\r\n",    safe_strncpy0(s, ctest->rcoun, 69));
    g_string_append_printf(gs, "RPhon=%s\r\n",    safe_strncpy0(s, ctest->rphon, 69));
    g_string_append_printf(gs, "RHBBS=%s\r\n",    safe_strncpy0(s, ctest->rhbbs, 69));
    g_string_append_printf(gs, "MOpe1=%s\r\n", z_str_uc(safe_strncpy0(s, b->mope1, 69)));
    g_string_append_printf(gs, "MOpe2=%s\r\n", z_str_uc(safe_strncpy0(s, b->mope2, 69)));
    g_string_append_printf(gs, "STXEq=%s\r\n",    safe_strncpy0(s, b->stxeq, 69));
    g_string_append_printf(gs, "SPowe=%s\r\n",    safe_strncpy0(s, b->spowe, 69));
    g_string_append_printf(gs, "SRXEq=%s\r\n",    safe_strncpy0(s, b->srxeq, 69));
    g_string_append_printf(gs, "SAnte=%s\r\n",    safe_strncpy0(s, b->sante, 69));
    g_string_append_printf(gs, "SAntH=%s\r\n",    safe_strncpy0(s, b->santh, 69));
    qsomult = ctest->qsomult;
    if (ctest->qsop_method==16) qsomult = qsomult16(b);
	g_string_append_printf(gs, "CQSOs=%d;%d\r\n",    b->stats->nqsos, qsomult * b->qsomultb);         
    g_string_append_printf(gs, "CQSOP=%d\r\n",       b->stats->nqsop);            
    g_string_append_printf(gs, "CWWLs=%d;%d;%d\r\n", g_hash_table_size(b->stats->wwls),  ctest->wwlbonu, ctest->wwlmult==0 ? 1 : ctest->wwlmult);  
    g_string_append_printf(gs, "CWWLB=%d\r\n",       g_hash_table_size(b->stats->wwls) * ctest->wwlbonu);
    g_string_append_printf(gs, "CExcs=%d;%d;%d\r\n", b->stats->nexcp,  ctest->excbonu, ctest->excmult==0 ? 1 : ctest->excmult); 
    g_string_append_printf(gs, "CExcB=%d\r\n",       g_hash_table_size(b->stats->excs) * ctest->excbonu);             
    g_string_append_printf(gs, "CDXCs=%d;%d;%d\r\n", g_hash_table_size(b->stats->dxcs),  ctest->dxcbonu, ctest->dxcmult==0 ? 1 : ctest->dxcmult); 
    g_string_append_printf(gs, "CDXCB=%d\r\n",       g_hash_table_size(b->stats->dxcs) * ctest->dxcbonu);
    g_string_append_printf(gs, "CToSc=%d\r\n",       b->stats->ntotal); 
    g_string_append_printf(gs, "CODXC=%s;",  z_str_uc(safe_strncpy0(s, b->stats->odxcall, 20)));
    g_string_append_printf(gs, "%s;%d\r\n",    z_str_uc(safe_strncpy0(s, b->stats->odxwwl,  20)), b->stats->odxqrb_int);  
    
    ret=fprintf(f, "%s", gs->str) != gs->len;
    g_string_free(gs, TRUE);
    
    return ret;
}

static int write_edi_empty_remarks(struct band *b, struct config_band *confb, FILE *f){
    char s[1024]; 
    int ret;
    GString *gs;

    
    gs = g_string_sized_new(100);
    g_string_append_printf(gs, "[Remarks]\r\n");
    if (b->remarks && b->remarks[0]=='[') g_string_append_printf(gs, " ");
    g_string_append_printf(gs, "%s", safe_strncpy0(s, b->remarks, 1024));
    g_string_append_printf(gs, "\r\n");                    
    
    ret=fprintf(f, "%s", gs->str) != gs->len;
    g_string_free(gs, TRUE);
    
    return ret;
}   

static int write_edi_remarks(struct band *b, struct config_band *confb, FILE *f){
    char s[1024];
    struct qso *q;
    GString *gs;
    int ret;
    int i;

    gs = g_string_sized_new(1024);
    
    g_string_append_printf(gs, "[Remarks]\r\n");
    if (b->remarks && b->remarks[0]=='[') g_string_append_printf(gs, " ");
    g_string_append_printf(gs, "%s", safe_strncpy0(s, b->remarks, 1024));
    g_string_append_printf(gs, "\r\n");                    

    g_string_append_printf(gs, "[TUCNAK extension]\r\n");
    g_string_append_printf(gs, "default_rs=%s\r\n",  ctest->default_rs);
    g_string_append_printf(gs, "default_rst=%s\r\n", ctest->default_rst);
    g_string_append_printf(gs, "prefmult=%d\r\n", ctest->prefmult);
    g_string_append_printf(gs, "prefglob=%d\r\n", ctest->prefglob);
    g_string_append_printf(gs, "dxcbonu=%d\r\n", ctest->dxcbonu);
    g_string_append_printf(gs, "dxcmult=%d\r\n", ctest->dxcmult);
    g_string_append_printf(gs, "excused=%d\r\n", ctest->excused);
    g_string_append_printf(gs, "exctype=%d\r\n", ctest->exctype);
    g_string_append_printf(gs, "excname=%s\r\n", ctest->excname);
    g_string_append_printf(gs, "excbonu=%d\r\n", ctest->excbonu);
    g_string_append_printf(gs, "excmult=%d\r\n", ctest->excmult);
    g_string_append_printf(gs, "exccfm=%d\r\n",  ctest->exccfm);
    g_string_append_printf(gs, "qsoused=%d\r\n", ctest->qsoused);
    g_string_append_printf(gs, "qsomult=%d\r\n", ctest->qsomult);
    g_string_append_printf(gs, "qsomultb=%d\r\n", b->qsomultb);
    g_string_append_printf(gs, "qsoglob=%d\r\n", ctest->qsoglob);
    g_string_append_printf(gs, "qsop_method=%d\r\n",  ctest->qsop_method);
    g_string_append_printf(gs, "rstused=%d\r\n", ctest->rstused);
    g_string_append_printf(gs, "defrstr=%d\r\n", ctest->defrstr);
    g_string_append_printf(gs, "total_method=%d\r\n", ctest->total_method);
    g_string_append_printf(gs, "wwltype=%d\r\n", ctest->wwltype);
    g_string_append_printf(gs, "wwlused=%d\r\n", ctest->wwlused);
    g_string_append_printf(gs, "wwlbonu=%d\r\n", ctest->wwlbonu);
    g_string_append_printf(gs, "wwlmult=%d\r\n", ctest->wwlmult);
    g_string_append_printf(gs, "wwlcfm=%d\r\n", ctest->wwlcfm);
    g_string_append_printf(gs, "tttype=%d\r\n", ctest->tttype);
    g_string_append_printf(gs, "expmode=%d\r\n", ctest->expmode);
	g_string_append_printf(gs, "phase=%d\r\n", ctest->phase);

    g_string_append_printf(gs, "bandchar=%c\r\n", b->bandchar);
//    g_string_append_printf(gs, "bandmulti=%d\r\n", b->bandmulti);
    g_string_append_printf(gs, "mode=%d\r\n", gses->mode);
    g_string_append_printf(gs, "operator=%s\r\n", b->operator_);
    g_string_append_printf(gs, "psect=%d\r\n", b->psect);
    g_string_append_printf(gs, "opsect=%s\r\n", b->opsect);
    g_string_append_printf(gs, "readonly=%d\r\n", b->readonly);
    g_string_append_printf(gs, "saveid=%d\r\n", b->saveid);
	g_string_append_printf(gs, "skedqrg=%s\r\n", b->skedqrg);
	g_string_append_printf(gs, "qrg=%1.0f\r\n", b->qrg);

    for (i=0; i< b->qsos->len; i++){
        q = get_qso(b, i); 
        
        g_string_append_printf(gs, "qso%d=", i);
        add_qso_str3(gs, q, b);
        
        /*g_string_append_printf(gs, "%s\r\n",gs->str);*/
        g_string_append_printf(gs, "\r\n");
    }
    
    ret=fprintf(f, "%s", gs->str) != gs->len;
    g_string_free(gs, TRUE);
    
    return ret;
}   


static int write_edi_qsos(struct band *b, struct config_band *confb, FILE *f){
    struct qso *q;
    GString *gs;
    int i;
    int ret;

    gs = g_string_new("");
    
    g_string_append_printf(gs, "[QSORecords;%d]\r\n", b->qsos->len);
    
    for (i=0; i<b->qsos->len; i++){
        q = get_qso(b, i); 
       
        add_qso_str1(gs, q, b);
        add_qso_str2(gs, q, b);
        
        g_string_append_printf(gs, "\r\n");
        /*g_string_append_printf(gs, "%s\r\n", gs->str);*/
    }
    
    g_string_append_printf(gs, "[END;TUCNAK-%s ver. %s]\r\n", Z_PLATFORM, VERSION);
    ret=fprintf(f, "%s", gs->str) != gs->len;
    g_string_free(gs, TRUE);
    
    return ret;
}


static int write_edi_unfi(struct band *b, struct config_band *confb, FILE *f){
    int i;
    gchar *c;
    GString *gs;
    int ret;

    gs = g_string_new("");
    
    for (i=0; i<b->unfi->items->len; i++){
        c = (gchar *) g_ptr_array_index(b->unfi->items, i);
        g_string_append_printf(gs, "unfinished%d=%s\r\n", i, c);
    }
    ret=fprintf(f, "%s", gs->str) != gs->len;
    g_string_free(gs, TRUE);
    
    return ret;
}

static int write_edi_sked(struct band *b, struct config_band *confb, FILE *f){
    int i;
    GString *gs;
    int ret;
    struct sked *sked;
    struct zstring *zs;

    gs = g_string_new("");
    
    for (i=0; i<b->skeds->len; i++){
        sked = (struct sked *) g_ptr_array_index(b->skeds, i);
        zs = sked_format(sked);
        g_string_append_printf(gs, "sked%d=%s\r\n", i, zs->str);
        zfree(zs);
    }
    ret=fprintf(f, "%s", gs->str) != gs->len;
    g_string_free(gs, TRUE);
    
    return ret;
}


int export_all_bands_edi(void){
    struct band *band;
    struct config_band *confb;
    int i, err;
    FILE *f;
    char callbuf[20];
    int ignoreerror=0;
    
    if (!ctest) return -1;
    
	menu_fillop(GINT_TO_POINTER(0));

    /*dbg("export_all_bands_edi()\n");*/
    for (i=0; i<ctest->bands->len; i++){
        char *section = NULL;
        
        band = (struct band *)g_ptr_array_index(ctest->bands, i);
        confb = (struct config_band *)get_config_band_by_bandchar(band->bandchar);

		progress(VTEXT(T_EXPORTING), band->bandname);
		zg_free0(band->edifile);
        stats_thread_join(band);
        if (band->stats->nqsos <=0) continue;

		switch (band->psect){
			case 0:	section = confb->ok_section_multi; break;
			case 1:	section = confb->ok_section_single; break;
			case 2:	section = "CH"; break;
			case 3:	section = confb->opsect; break;
		}
        if (section && *section)
            band->edifile = g_strdup_printf("%s/%s%s.edi",
                            ctest->directory,
                            section,
                            z_get_raw_call(callbuf,ctest->pcall));
        else
            band->edifile = g_strdup_printf("%s/%s_%c.edi",
                            ctest->directory,
                            z_get_raw_call(callbuf,ctest->pcall),
                            band->bandchar);
		z_wokna(band->edifile);
        f=fopen(band->edifile, "wb"); /* must be b for windoze */
        if (!f) {
            if (!ignoreerror) { errbox(VTEXT(T_CANT_WRITE), errno); ignoreerror=1;}
			progress(NULL);
            return -1;
        }
        err = 0;
        err|=write_edi_header        (band,confb,f);
        err|=write_edi_empty_remarks (band,confb,f);
        err|=write_edi_qsos          (band,confb,f);
        err|=fclose(f);
        if (err) {
            if (!ignoreerror) { errbox(VTEXT(T_CANT_WRITE), 0); ignoreerror=1; }
			progress(NULL);
            return -1;
        }
        log_addf(VTEXT(T_SAVED), band->edifile);
        
        fprintf(band->swap, "SE %d\n", ++band->saveid);
        fflush(band->swap);
        
    }
	progress(NULL);
    return 0;
}

static gchar *get_ctest_directory(int floppy){
    gchar *dir;
    const char *c;
    
    if (floppy==0){
        dir = g_strdup(ctest->directory);
    }else{
        //char *c1, *c2;
        
        if (!cfg->as_floppy_path || strlen(cfg->as_floppy_path)==0) return NULL;
        if (!cfg->as_floppy_aq) return NULL;
        
        //c1=c2=NULL;
		c = z_filename(ctest->directory);
		if (c != NULL){
        //if (regmatch(ctest->directory, ".*\\/(.*)", &c1, &c2, NULL)==0){
            dir = g_strdup_printf("%s/%s", cfg->as_floppy_path, c);
        }else{
            dir = g_strdup_printf("%s/%s", cfg->as_floppy_path, ctest->directory);
        }
        
        //if (c1) g_free(c1);
        //if (c2) g_free(c2);
    }
    return dir;
}

int save_all_bands_txt(int autosave){
    struct band *band;
    struct config_band *confb;
    int j, i, err, gerr;
    gchar *filename, *dir;
    FILE *f;
    int ignoreerror=0;
    int floppy_mounted,nm_showed;
    
    //dbg("save_all_bands_txt(%d)\n", autosave);
    
    if (!ctest) return -1;
    
    nm_showed=0;
	floppy_mounted = is_in_mtab(cfg->as_floppy_path);
	if (cfg->as_floppy_path && !*cfg->as_floppy_path){
		nm_showed = 1;	 // dont show error when no floppy is defined
	}


    
	gerr = 0;
    for (i=0; i<ctest->bands->len; i++){
        for (j=0; j<2; j++){
            band = (struct band *)g_ptr_array_index(ctest->bands, i);
            confb = (struct config_band *)get_config_band_by_bandchar(band->bandchar);
/*            dbg("  %c dirty=%d\n", band->bandchar, band->dirty_save); */

            dir = get_ctest_directory(j);
            if (!dir) continue;
            z_mkdir_p(dir, 0775);

            if (autosave == 1 && !band->dirty_save) {
                g_free(dir);
                continue;
            }
            
            if (j==0){
                if (autosave && autosave!=1) {
                    g_free(dir);
                    continue;
                }
            }else{ /* floppy */
                if (autosave && autosave!=2) {
                    g_free(dir);
                    continue;
                }
				if (nm_showed) {
                    g_free(dir);
                    continue;
                }
                if (!floppy_mounted && !nm_showed) {
                    log_addf(VTEXT(T_NOT_MOUNTED_S), cfg->as_floppy_path);
                    nm_showed=1;
                    g_free(dir);
					continue;
                }
            }
            
            stats_thread_join(band);
            
            filename = g_strdup_printf("%s/%c.txt", dir, z_char_lc(band->bandchar));
			z_wokna(filename);
            g_free(dir);
            
            //dbg("  saving filename '%s'\n", filename);
            f=fopen(filename,"wb"); /* must be b for windoze */
            if (!f) {
                gchar *c;
                c = g_strdup_printf(VTEXT(T_CANT_WRITE_S), filename);
                log_addf(c);
                g_free(c);
                if (j==0){
                    c = g_strdup_printf(VTEXT(T_CANT_WRITE_S), filename);
                }else{
                    c = g_strdup_printf("Can't open file '%s' for writing\nTry to mount floppy or disable\nMenu->Setup->Autosave->Path To Floppy", filename);
                }
                
                if (!ignoreerror) { errbox(c, errno); ignoreerror=1;}
                g_free(c);    
                g_free(filename);
                continue;
            }
            err = 0;
            err|=write_edi_header  (band,confb,f);
            err|=write_edi_remarks (band,confb,f);
            err|=write_edi_unfi    (band,confb,f);
            err|=write_edi_sked    (band,confb,f);
            err|=write_edi_qsos    (band,confb,f);
            err|=fclose(f);
            if (err) {    
                log_addf(VTEXT(T_CANT_WRITE_S), filename);
                if (!ignoreerror) { errbox(VTEXT(T_CANT_WRITE), 0); ignoreerror=1;}
                g_free(filename);
                continue;
            }
			gerr |= err;
            band->dirty_save = 0;
            fprintf(band->swap, "ST %d\n", band->saveid);
            fflush(band->swap);
            g_free(filename);
        }
        band->saveid++;
    }

	if (!gerr){
		if (!autosave) log_addf(VTEXT(T_SAVED_S), "contest");
	}
    if (!autosave){
        ctest->as_disk_qsonr = cfg->as_disk_aq;
        ctest->as_floppy_qsonr = cfg->as_floppy_aq;
    }



    for (j=0; j<2; j++){
        gchar *dir;

        
        if (j==0){
            if (autosave && autosave!=1) continue;
        }else{ /* floppy */
            if (autosave && autosave!=2) continue;
        }
            
        dir = get_ctest_directory(j);
        if (!dir) continue;
      
        
        if (j==1){ /* floppy */
		  	if (nm_showed) {
                g_free(dir);
                continue;
            }
            filename = g_strdup_printf("%s/desc",dir);
			z_wokna(filename);
            save_desc_to_file(filename);
            g_free(filename);
        }
        
        if (j==1){ /* save only contents of fifo to ctest/log on floppy */
            filename = g_strdup_printf("%s/log",dir);
			z_wokna(filename);
            save_fifo_to_file(glog, filename);
            g_free(filename);
        }
    
        filename = g_strdup_printf("%s/talk",dir);
		z_wokna(filename);
        save_fifo_to_file(gtalk, filename);
        g_free(filename);
    
        filename = g_strdup_printf("%s/spy", dir);  
		z_wokna(filename);
        save_spypeers_to_file(filename); /* called also in control.c */
        g_free(filename);
        
        filename = g_strdup_printf("%s/hicalls", dir);  
		z_wokna(filename);
        save_hicalls_to_file(filename);
        g_free(filename);

        filename = g_strdup_printf("%s/qrv", dir);  
		z_wokna(filename);
        save_qrv_to_file(filename);
        g_free(filename);

        filename = g_strdup_printf("%s/chart", dir);  
		z_wokna(filename);
        save_chart_to_file(filename);
        g_free(filename);

        g_free(dir);
    }
    
	save_cw(cw, 0);
	save_namedb(namedb, 0);


    return 0;
}


static GHashTable *load_edi_until(FILE *f, GHashTable *hash, gchar *until){
    GString *gs;
    gchar *c;
    gchar **a;
    gchar *k, *v;
    gpointer orig_key, orig_value;
    
    gs=g_string_new("");
    
    if (!hash) hash=g_hash_table_new(g_str_hash, g_str_equal);
 
    while( (c = zfile_fgets(gs, f, 0)) != NULL){
/*        dbg("load_edi_until   read '%s'\n", c);*/
        if (regcmpi(c, until)==0) break; 
        
        a = g_strsplit(c, "=", 2);
        if (!a) continue;

        if (!a[0] || !a[1]) {
            g_strfreev(a);
            continue;
        }
        g_strstrip(a[0]);
        g_strchomp(a[1]); 

        k=z_str_lc(g_strdup(a[0]));
        v=g_strdup(a[1]);

        if (g_hash_table_lookup_extended(hash, (gpointer)k, &orig_key, &orig_value)){
            g_hash_table_remove(hash, orig_key);
            g_free(orig_key);
            g_free(orig_value);
        }
        g_hash_table_insert(hash, k, v);
                
/*        dbg("load_edi_until load key=%p '%s'    value=%p '%s'\n", k,k, v, v);*/

        g_strfreev(a);
    }
/*    dbg("load_edi_until END %s\n",c);*/
    g_string_free(gs, 1);
    return hash;
}

static gchar *load_edi_remarks_until(FILE *f, gchar *until){
    GString *gs;
    gchar *c;
    gchar *ret,*tmp;
    
    gs=g_string_new("");
    
    ret=NULL;
    while( (c = zfile_fgets(gs, f, 0)) != NULL){
/*        dbg("load_edi_remarks_until   read '%s'\n", c);*/
        if (regcmpi(c, until)==0) break; 
        if (ret) {
            tmp=ret;
            g_free(ret);
            ret=g_strconcat(tmp," ",c, NULL);
        }else{
            ret=g_strdup(c);
        }
    }
/*    dbg("load_edi_remarks_untilEND %s\n",c);*/
    g_string_free(gs, 1);
    return ret;
}


static void array_free(gpointer item){
    gchar **a = (gchar **)item;
    g_strfreev(a);
}

static GPtrArray *load_edi_qsos_until(FILE *f, gchar *until){
    GString *gs;
    GPtrArray *array;
    gchar *c;
    gchar **a;
    int i;
    
    gs=g_string_new("");
    
	array = g_ptr_array_new_with_free_func(array_free);
 
    while( (c = zfile_fgets(gs, f, 0)) != NULL){
/*        dbg("load_edi_qsos_unti: '%s'\n", c);*/
        if (regcmpi(c, until)==0) break; 
        
        a = g_strsplit(c, ";", 11);  /* 11th is "N;N;N" */
        if (!a) continue;

        for (i=0;i<11;i++){
            if (!a[i]) goto x;
            g_strstrip(a[i]);
        } 

/*        dbg("load_edi_qsos_until: add  '%s'\n", c);*/
        g_ptr_array_add(array, (gpointer)a);

x:;        
    }
/*    dbg("load_edi_qsos_until: END '%s' \n", c);*/
    g_string_free(gs, 1);
    return array;
}

#if 0
static void skip_edi_until(FILE *f, gchar *until){
    GString *gs;
    gchar *c;
    
    gs=g_string_new("");
    
    while( (c = zfile_fgets(gs, f, 0)) != NULL){
 /*       dbg("skip_edi_until: read '%s'\n", c);*/
        if (regcmpi(c, until)==0) break; 
    }
/*    dbg("skip_edi_until: END '%s' \n", c);*/
    g_string_free(gs, 1);
}
#endif

static gboolean free_item(gpointer key, gpointer value, gpointer x){
    g_free(key);
    g_free(value);
    return TRUE;
}

static void destroy_string_hash(GHashTable *hash){
    g_hash_table_foreach_remove(hash, free_item, NULL);
    g_hash_table_destroy(hash);
}


static void add_qsos_from_mem(struct band *b, GHashTable *hash, GPtrArray *qsos, const gchar *date){
    gchar **items, **items2;
    int i, j;
    gchar *c, *add;
    struct qso *q;
    char s[10];
    time_t now;

    now = time(NULL);

    for (i=0; i<qsos->len; i++){
        items = (gchar **) g_ptr_array_index(qsos, i);

        q = g_new0(struct qso, 1);
        if (strlen(items[0])>6) 
            q->date_str = g_strdup(items[0]);
        else
            q->date_str = g_strdup_printf("%s%s", 
                    safe_strncpy(s, date, 3), items[0]);

        q->time_str = g_strdup(items[1]);
        q->callsign = g_strdup(items[2]);
        if (strcasecmp(q->callsign, "ERROR")==0) q->error=1;
        q->mode     = atoi(items[3]);
        q->rsts     = g_strdup(items[4]);
        q->qsonrs   = g_strdup(items[5]);
        q->rstr     = g_strdup(items[6]);
        q->qsonrr   = g_strdup(items[7]);
        q->exc      = g_strdup(items[8]);
        q->locator  = g_strdup(items[9]);
        
		//g_strfreev(items); freed after for

        c = g_strdup_printf("qso%d", i);
        add = (char *)g_hash_table_lookup(hash, c);
        g_free(c);
        if (!add){
            char century[3];
            safe_strncpy0(century, q->date_str, 3);
            add=g_strdup_printf("%s;%s;%d;%s;"
                                "%s;%s;%d;",    
                    gnet->myid, fixsemi(b->operator_), (int)now, "",
                    century, "", -1);
            items2 = g_strsplit(add, ";", 0);
            g_free(add);
        }else{
            items2 = g_strsplit(add, ";", 0);
        }
       
        for (j=0;j<=4;j++) if (!items2[j]) goto x;
        
        q->source    = g_strdup(items2[0]);
        q->operator_ = g_strdup(items2[1]);
        fixsemi(q->operator_);
        q->stamp    = atoi(items2[2]);
        if (!items2[5]){
            q->remark   = g_strdup("");
        }else{
            q->remark   = g_strdup(items2[5]);
        }

        if (q->error && *items2[3]){
            g_free(q->callsign);
            q->callsign = g_strdup(items2[3]);
        }
        
        
        c = q->date_str;
        if (strlen(c)>2 && items2[4]) {
            q->date_str = g_strdup_printf("%s%s", items2[4], c+2);
            g_free(c); 
        }
        

        if (items2[6]){
            q->ser_id=atoi(items2[6]);
            edi_serid_used=1;
        }else{
            q->ser_id=-1; /* filled in add_qso_to_index and rewritten after loop. only for compatibility */
        }

        if (items2[6] && items2[7]){
            q->qrg = atof(items2[7]);
        }else{
            q->qrg = 0.0; 
        }

		if (items2[6] && items2[7] && items2[8]){
			q->phase = atoi(items2[8]);
			if (q->phase > ctest->phase) 
				ctest->phase = q->phase;
		}
		else{
			q->phase = 1;
		}
        
        g_strfreev(items2);
        compute_qrbqtf(q);
        add_qso(b, q);
        update_stats(b, b->stats, q);
        
        
x:;
    }
    g_ptr_array_free(qsos, TRUE);
    recalc_allb_stats();
    minute_stats(b);
/*    g_hash_table_foreach(ctest->bystamp, foreach_source_print, NULL);*/

    
}


static void add_unfi_from_mem(struct band *b, GHashTable *hash){
    int i;
    gchar *add, *c;
    
    b->unfi->withouttime=1;
    for (i=0;;i++){
        c = g_strdup_printf("unfinished%d", i);
        add = (char *)g_hash_table_lookup(hash, c);
        g_free(c);
        if (!add) break;
/*        dbg("unfinished=''\n", add);*/
        fifo_adds(b->unfi, add);
    }
    b->unfi->withouttime=0;
    
}

static void add_sked_from_mem(struct band *b, GHashTable *hash){
    int i;
    gchar *add, *c;
    struct zstring *zs;
    struct sked *sked;
    
    for (i=0;;i++){
        c = g_strdup_printf("sked%d", i);
        add = (char *)g_hash_table_lookup(hash, c);
        g_free(c);
        if (!add) break;
//        dbg("sked=''\n", add);
        zs = zstrdup(add);
        sked = sked_parse(zs);
        zfree(zs);
        if (!sked) {
            dbg("bad format of sked '%s'\n", add);
            continue;
        }
        g_ptr_array_add(b->skeds, sked);
        sked->worked = get_qso_by_callsign(b, sked->callsign) != NULL;
    }
}


static int select_enable_all(const char *dir, const struct dirent *de){
    return 1;
}


#define REPLACE(from,to) \
    c = (char *)g_hash_table_lookup(hash, from);\
    if (c && !g_hash_table_lookup(hash, to)){\
        g_hash_table_insert(hash, g_strdup(to), g_strdup(c));\
        dbg("replacing %s to %s with %s\n", from, to, c); \
    }


static int convert_bo_s_hash(GHashTable *hash, const char *dir){
    struct config_band *tmpcb;
    gchar *c, *date;

    c = (char *)g_hash_table_lookup(hash, "band");
    if (c){
        tmpcb = get_config_band_by_bandchar(z_char_lc(c[0]));
        if (tmpcb){
            if (tmpcb->pband && !g_hash_table_lookup(hash, "pband"))
                g_hash_table_insert(hash, g_strdup("pband"), g_strdup(tmpcb->pband));
        }
    }

    date = g_strdup(dir);
    c = strchr(date,'.');
    if (c) *c='\0';
    if (!g_hash_table_lookup(hash, "tdate"))
        g_hash_table_insert(hash, g_strdup("tdate"), g_strdup(date));
    g_free(date);        

    REPLACE("comment", "tname");
    REPLACE("owncall", "pcall");
    REPLACE("ownwwl",  "pwwlo");
    REPLACE("ownoptionalexchange", "pexch");
    REPLACE("band", "bandchar");
    REPLACE("qsopointsmultiplier", "qsomult");
    REPLACE("qsocalcmethod", "qsop_method");
    REPLACE("wwlbonus", "wwlbonu");
    REPLACE("wwlmultiplier", "wwlmult");
    REPLACE("dxccbonus", "dxcbonu");
    REPLACE("dxccmultiplier", "dxcmult");
    REPLACE("optionalexchangebonus", "excbonu");
    REPLACE("optionalexchangemultiplier", "excmult");
    REPLACE("totalcalcmethod", "total_method");
    REPLACE("operator0", "operator");
    return 0;
}

//int *pnn = NULL;
/* loads edi and txt */
void load_contest_edi(const gchar *date, int edi){
    struct dirent **namelist=NULL;
    int nn=0; // probably buggy register optimisation in gcc 4.3.2 amd64
    int i;
    gchar *datedir, *file, *pband;
    struct stat st;
    char *ext, *c;
    FILE *f, *lockfile,*logfile;
    GHashTable *hash;
    struct band *b;
    static char ss[1024];
    gint saveid=-1;
    gchar *remarks;
    time_t now;
    struct tm tm;
    int nowdate_int, ctestdate_int;
    
    file = NULL;
    datedir = NULL;
    
	progress(VTEXT(T_LOADING_CONTEST), date);

    c=g_strdup_printf("%s/%s/desc.lock", logs_dir, date);
	z_wokna(c);
    lockfile = fopen(c, "w");
    if (!lockfile){
        g_snprintf(ss,1000, VTEXT(T_CANT_OPEN_S),c);
        g_free(c);
        msg_box(NULL, VTEXT(T_ERROR), AL_CENTER, ss, NULL, 1, VTEXT(T_OK), NULL, B_ENTER | B_ESC);
        goto x;
    }
    
    if (z_lockf(fileno(lockfile), F_TLOCK, 0, 1)){ 	 
        fclose(lockfile); lockfile=NULL;
        g_snprintf(ss,1000, VTEXT(T_CANT_LOCK_S),c);
        g_free(c);
        msg_box(NULL, VTEXT(T_ERROR), AL_CENTER, ss, NULL, 1, VTEXT(T_OK), NULL, B_ENTER | B_ESC);
        goto x;
    }
    g_free(c);
                
    
    
    datedir = g_strdup_printf("%s/%s", logs_dir, date);
   
    file = g_strdup_printf("%s/log", datedir);
    load_fifo_from_file(glog, file,0);
    fifo_addfq(glog, VTEXT(T_LOADING_CTEST_S), date); 
    zg_free0(file);

	progress(VTEXT(T_LOADING_LOGFILE));
    c=g_strdup_printf("%s/%s/log", logs_dir, date);
    logfile = fopen(c, "at");
    if (!logfile){
        g_snprintf(ss,1000, VTEXT(T_CANT_OPEN_S),c);
        g_free(c);
        msg_box(NULL, VTEXT(T_ERROR), AL_CENTER, ss, NULL, 1, VTEXT(T_OK), NULL, B_ENTER | B_ESC);
        goto x;
    }
    g_free(c);
    setvbuf(logfile, NULL, _IONBF, 0);
    fprintf(logfile, VTEXT(T_LOADING_CTEST_S), date); fprintf(logfile, "\n");
    
    
	progress(VTEXT(T_LOADING_TALK));
    file = g_strdup_printf("%s/talk", datedir);
    load_fifo_from_file(gtalk, file,1);
    fifo_addfq(gtalk, VTEXT(T_LOADING_CTEST_S), date);
    zg_free0(file);


    nn = z_scandir(datedir, &namelist, select_enable_all, z_scandir_alphasort);
    if (nn<=0) {
        errbox(VTEXT(T_NO_FILES), 0);
        fclose(lockfile); 
        fclose(logfile); 
        goto x;
    }
    
    edi_serid_used=0;
    for (i=0; i<nn; i++){
        GString *gs;

		progress(VTEXT(T_SEARCH_FILES));
        ext = edi ? "[a-z]\\.edi$" : "[a-z]\\.txt$";
    
        if (regcmp(namelist[i]->d_name, ext)) continue;

        zg_free0(file);
        file = g_strconcat(datedir, "/", namelist[i]->d_name, NULL); 
        /*dbg("file='%s'\n", file);*/

        if (stat(file, &st)) continue;
        if (!S_ISREG(st.st_mode)) continue;
       
        f = fopen(file, "rt");
        if (!f) continue;
        if (!edi){
            hash = load_edi_until(f, NULL, "^\\[remarks\\]");
            remarks = load_edi_remarks_until(f, "^\\[tucnak extension\\]");
 /*           skip_edi_until(f, "^\\[tucnak extension\\]");*/
            load_edi_until(f, hash, "^\\[qsorecords");
        }else{
            hash = load_edi_until(f, NULL, "^\\[remarks\\]");
            remarks = load_edi_remarks_until(f, "^\\[qsorecords");
        }
        GPtrArray *qsos = load_edi_qsos_until(f, "^\\[end;");
        
        fclose(f);
        
        convert_bo_s_hash(hash, date);

        pband = (char *)g_hash_table_lookup(hash, "pband"); 
        /*dbg("pband='%s'\n", pband);*/
        if (!pband) {
            struct config_band *tmpcb;
            gchar *c;
            c = (char *)g_hash_table_lookup(hash, "band");
            if (!c) goto destroy;
            tmpcb = get_config_band_by_bandchar(z_char_lc(c[0]));
            if (!tmpcb) goto destroy;
            pband = tmpcb->pband;
            if (!pband){
destroy:;         
                zg_free0(remarks);       
                destroy_string_hash(hash);
                continue;
            }
        }

        if (find_band_by_pband(pband)){
            log_addf(VTEXT(T_BAND_EXIST_SS), pband, file);
            g_ptr_array_free(qsos, TRUE);
            goto destroy;
        }

        if (!ctest) {
            init_ctest();
            load_ctest_from_mem(ctest, datedir, hash);
			update_hw();
            maps_reload();
			maps_update_showwwls();
#ifdef Z_HAVE_SDL
			rain_reload();
#endif
        }
        
        b = init_band(NULL, hash, NULL, NULL);
        if (!b) {
          /*  dbg("load_contest_edi: b=NULL!\n");*/
            g_ptr_array_free(qsos, TRUE);
            goto destroy;
            
        }
		progress(VTEXT(T_LOADING_BAND), b->bandname);
        /* edi_serid_used=0; must be assigned but before band loop */
        add_qsos_from_mem(b, hash, qsos, date);
        add_unfi_from_mem(b, hash);
        add_sked_from_mem(b, hash);
        clear_tmpqsos(b, 1);
        destroy_string_hash(hash);  
        if (remarks){
            zg_free0(b->remarks);
            b->remarks=remarks;
        }      

        zg_free0(file);
        
        file = g_strconcat(datedir, "/", namelist[i]->d_name, NULL); 
        c = strstr(file,"txt");
        if (!c) continue;
        strcpy(c, "swp");
        /*dbg("swap='%s'  saveid=%d\n", file, b->saveid-1);*/
       
        f = fopen(file, "rt");
        if (!f) continue;
        gs = g_string_sized_new(100);
        while(zfile_fgets(gs, f, 0)!=NULL){
          /*      dbg("read '%s'\n", gs->str);*/
            if (strncmp(gs->str,"ST ",3)!=0) continue;
            saveid=atoi(gs->str+3);
/*            dbg("sid=%d\n", saveid);*/
            if (saveid == b->saveid-1) break;
            
        }
        if (saveid == b->saveid-1){
            b->ignoreswap = 1;
   /*         dbg("begin is %d\n", saveid);*/
            while(zfile_fgets(gs, f, 0)!=NULL){
//                dbg("read '%s'\n", gs->str);
                        
                if (strncmp(gs->str,"# ",2)==0){
                    process_input(b, gs->str+2, 0);
                    continue;
                }
                if (strncmp(gs->str,"CLR",3)==0){
                    clear_tmpqsos(b, 1);
                    continue;
                }
                if (strncmp(gs->str,"Q ",2)==0){
					gchar **items;
					items = g_strsplit(gs->str + 2, ";", 0);

					char *c = g_strdup_printf("%s%s", items[14], items[0]);
					process_input(b, c, 0);
					g_free(c);

					GString *t = g_string_new(items[1]);
					if (t->len > 2) g_string_insert(t, 2, ":");
					process_input(b, t->str, 0);
					g_string_free(t, TRUE);

					c = g_strdup_printf("%s'", items[4]);
					process_input(b, c, 0);
					g_free(c);

					c = g_strdup_printf("%s,", items[6]);
					process_input(b, c, 0);
					g_free(c);


					g_strfreev(items);
					
                    process_input(b, "", 0);
                    continue;
                }
                if (strncmp(gs->str,"O ",2)==0){
                    if (b->operator_) g_free(b->operator_);
                    b->operator_ = fixsemi(g_strdup(gs->str+2));
                    continue;
                }
                    
            }
            b->ignoreswap = 0;
        }
        fclose(f);
        g_string_free(gs, 1);
        //g_ptr_array_free(qsos, TRUE);
    }
    
    if (!ctest) {
        errbox(VTEXT(T_NO_BANDS), 0);
        fclose(lockfile); 
        fclose(logfile); 
        goto x;
    }
    if (ctest->bands->len==0){
        errbox(VTEXT(T_NO_BANDS), 0);
        free_ctest();
        goto x;
    }
    
    
    zg_free0(file);
    
	progress(VTEXT(T_LOADING_SPY));
    file = g_strdup_printf("%s/spy", datedir);
	z_wokna(file);
    load_spypeers_from_file(file);
    zg_free0(file);

	progress(VTEXT(T_LOADING_HICALLS));
    file = g_strdup_printf("%s/hicalls", datedir);
	z_wokna(file);
    load_hicalls_from_file(file);
    zg_free0(file);

	progress(VTEXT(T_LOADING_QRV));
    file = g_strdup_printf("%s/qrv", datedir);
	z_wokna(file);
    load_qrv_from_file(qrv, file);
    zg_free0(file);
    
	progress(VTEXT(T_LOADING_CHART));
    file = g_strdup_printf("%s/chart", datedir);
	z_wokna(file);
    load_chart_from_file(file);
    zg_free0(file);
    
	progress(VTEXT(T_SAVING_CONTEST));
    check_autosave();

	progress(VTEXT(T_UPD_INT_DATA));
    ctest->lockfile = lockfile;
    ctest->logfile = logfile;
    ctest->cdate = g_strdup(date);
    c = strchr(ctest->cdate, '.');
    if (c) *c='\0';

    now = time(NULL);
    gmtime_r(&now, &tm);
    nowdate_int = (tm.tm_year+1900)*10000 + (tm.tm_mon+1)*100 + tm.tm_mday;
    ctestdate_int = atoi(ctest->cdate);
    if (/* nowdate_int >= ctestdate_int &&*/ nowdate_int <= ctestdate_int + 2) 
        ctest->oldcontest = 0;
    else
        ctest->oldcontest = 1;
//    dbg("ctestdate=%d nowdate=%d oldcontest=%d\n", ctestdate_int, nowdate_int, ctest->oldcontest);

    
    if (!edi_serid_used){
        /* only for backward compatibility with version without ser_id in edi file */
        g_hash_table_foreach(ctest->bystamp, foreach_source_recalc_ser_id, NULL);
    }

    g_hash_table_foreach(ctest->bystamp, foreach_source_qsort_by_stamp, NULL);
    z_ptr_array_qsort(ctest->allqsos, compare_date_time_qsonrs);

    
    set_ctest_title();
    clear_exc(excdb);
    read_exc_files(excdb, ctest->exctype, ctest->excname);
    
	progress(VTEXT(T_CALC_STATS));
    recalc_allb_stats();
    for (i=0; i<ctest->bands->len; i++){
        struct band *b = (struct band *)g_ptr_array_index(ctest->bands, i);
        b->dirty_statsf = 1;
        recalc_statsfifo(b);
    }
    
    //dump_all_sources(ctest);
	progress(VTEXT(T_ANN_OVER_NET));
    net_send_ac();
	sw_shake_tmo = ztimeout_init(100000);        

    if (cfg->startband){
        struct band *b;
        b=find_band_by_pband(cfg->startband);
        if (b){
            progress(VTEXT(T_ACTIVATING_BAND), b->bandname);
            activate_band(b); /* b==NULL is handled by function */
        }
	}
	chart_reload();

#ifdef OCT8TOR
	struct config_band *cb = get_config_band_by_bandchar(aband->bandchar);
	oct8tor_send_band(goct8tor, cb->adifband);
#endif

	progress(VTEXT(T_UPDATING_WKD));
    qrv_recalc_wkd(qrv);
	progress(VTEXT(T_UPDATING_QRBQTF));
	qrv_recalc_qrbqtf(qrv);
	progress(VTEXT(T_UPDATING_GAIN));
    qrv_recalc_gst(qrv);
	progress(VTEXT(T_SEN_OVER_NET));
    net_send_operator();
    net_send_read_write_bands();
	net_send_talk();
	spypeer_send_requests();

x: 
	sw_shake_tmo = -1;
    //dbg("nnx=%d\n", nn);
//     dumpvar(nn);
//     dumpvar(i);
    if (namelist){
        for (i=0; i<nn; i++) free(namelist[i]);
        free(namelist);
    }
    zg_free0(datedir);   
    zg_free0(file);   
	progress(NULL);
}

void import_edi(void *xxx, char *filename){
    FILE *f;
    GHashTable *hash;
    GPtrArray *qsos;
    gchar *pband;
    struct band *band;
    
    
    f = fopen(filename, "rt");
    if (!f) {
        errbox(VTEXT(T_CANT_OPEN_S), errno, filename);
        return;
    }
    hash = load_edi_until(f, NULL, "^\\[qsorecords;");
    qsos = load_edi_qsos_until(f, "^\\[end;");
    fclose(f);

    pband = (char *)g_hash_table_lookup(hash, "pband"); 
    /*dbg("import_edi: pband='%s'\n", pband);*/
    
    band=find_band_by_pband(pband);
    if (!band){
        errbox(VTEXT(T_BAND_NOT_OPEN), 0);
        goto destroy;
    }

    edi_serid_used=0;    
    add_qsos_from_mem(band, hash, qsos, ctest->cdate);
destroy:;    
    destroy_string_hash(hash);  
    //zg_ptr_array_free_all(qsos);  
    redraw_later();
}

void import_swap(void *xxx, char *filename){
	FILE *f;
	f = fopen(filename, "rt");
	if (!f){
		char *c = g_strdup_printf(VTEXT(T_CANT_READ_S), filename);
        msg_box(getml(c, NULL), VTEXT(T_ERROR), AL_CENTER, c, NULL, 1, VTEXT(T_OK), NULL, B_ENTER | B_ESC);
	}
	add_qsos_from_swap(aband, f);
	fclose(f);
}

int save_desc_to_file(gchar *filename){
    gchar *pcall, *s;
    FILE *f;
    int ret;

    z_wokna(filename);
	f = fopen(filename, "wt");
    if (!f) return 1;
    
    pcall=g_strdup(ctest->pcall);
    s = g_strdup_printf("%s %s %s\n", ctest->cdate, z_str_uc(pcall), ctest->tname);    
    ret = fprintf(f, "%s", s) != strlen(s);
    g_free(pcall);
    g_free(s);
    fclose(f);
    return ret;
    
}
