/*
    Tucnak - VHF contest log
    Copyright (C) 2002-2023  Ladislav Vaiz <ok1zia@nagano.cz>
    and authors of web browser Links 0.96

    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.

    UTF-8 detect: ěščřžýáíé
*/


#include "header.h"
#include "bfu.h"
#include "control.h"
#include "cwdaemon.h"
#include "cwdb.h"
#include "cwwindow.h"
#include "chart.h"
#include "dwdb.h"
#include "edi.h"
#include "excdb.h"
#include "fifo.h"
#include "hf.h"
#include "inputln.h"
#include "kbdbind.h"
#include "kbd.h"
#include "kst.h"
#include "main.h"
#include "map.h"
#include "menu.h"
#include "misc.h"
#include "namedb.h"
#include "net.h"
#include "ntpq.h"
#include "qsodb.h"
#include "rain.h"
#include "rc.h"
#include "rotar.h"
#include "tsdl.h"
#include "session.h"
#include "sked.h"
#include "ssbd.h"
#include "state.h"
#include "stats.h"
#include "subwin.h"
#include "translate.h"
#include "tregex.h"
#include "trig.h"
#include "update.h"
#include "zosk.h"

int session_id = 1;


/*#ifdef Z_MSC
void android_restore_state(){
	GHashTable *state = NULL;
	int i;
    
    dbg("android_restore_state started gses=%p\n", gses);
#ifdef Z_MSC
	if (!state) state = g_hash_table_new(g_str_hash, g_str_equal);
	g_hash_table_insert(state, g_strdup("gses_il_cdata"), g_strdup("GSES INPUTLN"));
	g_hash_table_insert(state, g_strdup("ctest"), g_strdup("20130610.1"));
	for (i = 0; i < cfg->bands->len; i++){
		struct config_band *b = (struct config_band *)g_ptr_array_index(cfg->bands, i);
		g_hash_table_insert(state, g_strdup_printf("band%c_il_cdata", z_char_lc(b->bandchar)), g_strdup_printf("Band %c inputln", z_char_lc(b->bandchar)));
	}

	for	(i = 0; i < gses->subwins->len; i++){
		struct subwin *sw = (struct subwin *)g_ptr_array_index(gses->subwins, i);
		if (sw->il){
			g_hash_table_insert(state, g_strdup_printf("sw%d_il_cdata", i+1), g_strdup_printf("Subwin %d inputline", i+1));
		}
	}
	g_hash_table_insert(state, g_strdup("sw0il_cdata"), g_strdup("Talk"));
#endif

    do_restorestate(state);
	dbg("android_restore_state finished\n");
}
#endif*/

struct session *create_session(struct window *win)
{
 /*   struct terminal *term = win->term;*/
    struct session *ses;
    struct config_subwin *csw;
    int i, setontop = 0;
    
    ses = g_new0(struct session, 1);
    /*    dbg("create_session allocated %p\n", ses);*/
    ses->win = win;
    ses->id = session_id++;
	ses->sel_start = -1;
	ses->sel_stop = -1;
	ses->sel_min = INT32_MAX;
	ses->sel_max = -1;
    gses = ses;
    gses->hicalls=g_hash_table_new(g_str_hash, g_str_equal);    
    /**/
    /*memcpy(&ses->ds, &dds, sizeof(struct document_setup));*/

    ctest=NULL;
	update_hw();
        
    ses->subwins = g_ptr_array_new();
    sw_shake_tmo = ztimeout_init(100000);

    if (cfg->sws->len){
        for (i=0;i<cfg->sws->len;i++){
            csw=(struct config_subwin *)g_ptr_array_index(cfg->sws, i);
			new_subwin((enum sw_type)csw->type, -1);
        }
    }else{
        /* default values when no subwins are defined in tucnakrc */
        new_subwin(SWT_QSOS, -1);
        new_subwin(SWT_SKED, -1);
        new_subwin(SWT_TALK, -1);
        new_subwin(SWT_DXC, -1);
        new_subwin(SWT_UNFI, -1);
        new_subwin(SWT_STAT, -1);
        new_subwin(SWT_KST, -1);
        new_subwin(SWT_SHELL, -1);
        new_subwin(SWT_LOG, -1);

    }
    setontop = 1;
    sw_shake_tmo = -1;
      
        
    
    /*if (first_use) {
        first_use = 0;
        msg_box(NULL, VTEXT(T_WELCOME), AL_CZ | AL_EXTD_TEXT, VTEXT(T_WELCOME_TO_TUCNAK), "\n\n", VTEXT(T_BASIC_HELP), NULL, NULL, 1, VTEXT(T_OK), NULL, B_ENTER | B_ESC);
    }*/
    if (strlen(cfg->pcall)==0 || strlen(cfg->pwwlo)==0){
        zselect_bh_new(zsel, contest_def, GINT_TO_POINTER(1));
        first_contest_def=1;
    }

	if (opt_x) zselect_bh_new(zsel, translate, NULL);

    ses->il = g_new0(struct inputln,1);
    ses->il->upconvert = 1;
    ses->il->valid_chars = VALID_CHARS; 
    gses->qs = g_ptr_array_new();
    MUTEX_INIT(gses->qs);

	if (setontop){
        sw_set_ontop(0, 1);
        sw_set_ontop(0, 0);
	}
    log_adds(TRANSLATE("Please consider supporting - Menu Help, Support Tucnak"));
    return ses;
}

/*gboolean free_hicalls(gpointer key, gpointer value, gpointer user_data){
    g_free(key);
    g_free(user_data);
    return TRUE;
}		*/

void win_func(struct window *win, struct event *ev, int fw)
{
/*    if (ev->ev==EV_KBD) dbg("\n");*/
    //dbg("win_func [%d,%d,%d,%d]\n",ev->ev,ev->x,ev->y,ev->b);
    switch (ev->ev) {
        case EV_ABORT:
            sw_all_func(ev,fw);
            free_ctest();
            if (gses->timer_id) zselect_timer_kill(zsel, gses->timer_id);
#ifdef FALL
            if (gses->fall_id) zselect_timer_kill(zsel, gses->fall_id);
#endif
            free_subwins();
            inputln_func(gses->il, ev);
            g_free(gses->il);
            qs_thread_kill();
            zg_ptr_array_free_all(gses->qs);
            MUTEX_FREE(gses->qs);
            zg_free0(gses->qs_str);

            zg_hash_free(gses->hicalls);
/*		    g_hash_table_foreach_remove(gses->hicalls, free_hicalls, NULL);
			g_hash_table_destroy(gses->hicalls);*/

            if (gses->redraw_timer_id) zselect_timer_kill(zsel, gses->redraw_timer_id);
#ifdef Z_HAVE_SDL
            if (gses->update_rotar_timer_id) zselect_timer_kill(zsel, gses->update_rotar_timer_id);
            if (gses->bat_timer_id) zselect_timer_kill(zsel, gses->bat_timer_id);
#endif
            if (gses->skedw_timer_id > 0) {
                zselect_timer_kill(zsel, gses->skedw_timer_id); 
                gses->skedw_timer_id = 0;
            }
            // g_free(gses->ac_cq->cw_str); NO! it is "foreign key"
            g_free(gses->ac_cq);
            zg_free0(gses->asunriseset);
			if (gses->update){
				zhttp_free(gses->update);
				gses->update = NULL;
			}
			g_free(gses->callunder);
            /*g_free(gses); no, freeed in delete_window */
            gses=NULL;
            break;
        case EV_INIT:
            win->data = gses = create_session(win);
            
            if (ctest && aband) {
				inputln_func(aband->il,ev);
			}else{
				inputln_func(gses->il, ev);
				gses->il->enter = process_input_no_contest;
			}
            il_set_focus(INPUTLN(aband));
            gses->timer_id = zselect_timer_new(zsel, 1, time_func, NULL);
#ifdef FALL
            gses->fall_id = zselect_timer_new(zsel, 1000, fall_func, NULL);
#endif
#ifdef Z_HAVE_SDL
			zselect_timer_new(zsel, 1, bat_timer, NULL);
			grain = init_rain();
#endif
            gses->mode = MOD_SSB_SSB;
            gses->ac_cq = g_new0(struct cq, 1);
            gses->skedw_timer_id = 0;
           	update_tucnak(win_func, win_func);

        case EV_RESIZE:
#ifdef Z_HAVE_SDL
			if (gses->osk && ev->b == 0) {
				char *c = g_strdup(gses->osk->gs->str);
				int flags = gses->osk->flags;
				//dbg("zosk_free(%p %p)\n", gses->osk, gses->osk->surface);
				zosk_free(gses->osk);
				gses->osk = zosk_init(sdl->screen, flags, c);
				zosk_portrait(gses->osk);
				//dbg("zosk_inite(%p %p)\n", gses->osk, gses->osk->surface);
				g_free(c);
			}
#endif
     /*       dbg("win_func: EV_RESIZE %dx%d\n", term->x, term->y);*/
            fifo_resize(glog, 1, term->y-cfg->loglines, term->x-2, cfg->loglines);
       /*     draw_root_window();*/
            if (ctest) {
                int i;
                for (i=0;i<ctest->bands->len;i++) {
                    struct band *b;
                    b=(struct band*)g_ptr_array_index(ctest->bands,i);
                    inputln_func(b->il,ev);
                    /*b->il->band=b;*/
                }
            }
            inputln_func(gses->il, ev);
			gses->y1 = QSONR_HEIGHT;
			gses->y2 = QSONR_HEIGHT;
			gses->height1 = term->y - QSONR_HEIGHT - 4 - cfg->loglines;
			//gses->ily = term->y - 1 - cfg->loglines;
			//gses->tqy = term->y - 1 - cfg->loglines - DISP_QSOS;
			if (ctest && !ctest->oldcontest) {
				gses->height1 -= ctest->spypeers->len;
				//gses->ily -= ctest->spypeers->len;
				//gses->tqy -= ctest->spypeers->len;
			}
			 
			if (cfg->splitheight > 0){
				gses->height2 = cfg->splitheight;
				gses->height1 -= gses->height2 + 1;
				gses->y1 += gses->height2 + 1;
			}

            sw_all_func(ev, fw);
            redraw_later();
            break;
        case EV_REDRAW:
//			z_crash();
//			g_free(win_func);
            //aband->bandchar = 'x';
            if (!gses) return;
/*            dbg("win_func: EV_REDRAW\n");*/
            draw_root_window();
            inputln_func(INPUTLN(aband),ev);
            if (show_qs()){
			    MUTEX_LOCK(gses->qs);
                sw_qs_redraw();
				MUTEX_UNLOCK(gses->qs);
            }else{
                sw_ontop_func(ev, fw);
            }
            
            /*if (ctest && aband) {
                inputln_func(aband->il,ev);
                if (show_qs()){
                    sw_qs_redraw();
                }else{
                    sw_ontop_func(ev, fw);
                }
            }else{
                inputln_func(gses->il, ev);
                sw_ontop_func(ev, fw);
            } */
			if (cfg->splitheight > 0){
				draw_titles(QSONR_HEIGHT - 1, 1); 
				draw_titles(gses->y1 - 1, 0); 
			}else{
				draw_titles(QSONR_HEIGHT - 1, 0); 
			}
            break;
        case EV_KBD:
            send_event(ev);
            break;
        case EV_MOUSE:
            send_event(ev);
            break;
        default:
            error("ERROR: unknown event");
    }
#ifdef Z_ANDROID
    if (ev->ev == EV_INIT) {
        android_restore_state();
    }
#endif
/*#ifdef Z_MSC
	if (ev->ev == EV_INIT) {
		struct state *state = init_state();
		state_test(state);
		state_restore(state);
	}
#endif*/
}


void rxtx(void){
//    if (gses->win->prev->handler==cwwindow_func) return; //probably not working
    gses->tx=!gses->tx;
    if (gses->tx && can_tx(aband)){
        cq_abort(1);
        if (get_mode() == MOD_CW_CW){
            cwdaemon_ptt(cwda, 1, 1);
        }else{
            cwdaemon_ptt(cwda, 1, 0);
        }
        if (get_mode() == MOD_CW_CW){
            add_window(cwwindow_func, NULL);
#ifdef Z_HAVE_SDL
            if (gses && sdl) gses->icon = sdl->key;
#endif
        }
        peer_tx(aband, 1);
    }else{
        rx();
    }
    redraw_later();
}   

void esc(void){
    /*if (!ctest || !aband) return;*/
    if (gses->focused){ /* look at sw_dxc_kbd_func, ACT_ENTER */
        sw_unset_focus();
        il_set_focus(INPUTLN(aband));
    }else{
        rx();
    }
    
    redraw_later();
    //dbg("esc returning\n");
}


void rx(void){
    gses->tx=0;
    gses->tune=0;
    gses->extcq=EC_NONE;
    cq_abort(0);
    //dbg("rx: cq_abort returned\n");
    cwdaemon_ptt(cwda, 0, 0);
    peer_tx(aband, 0);
}

    /* for global events such as keying */
int preferred_func(struct event *ev){

	switch(ev->ev){
		case EV_KBD:
			switch (kbd_action(KM_MAIN, ev)) {
				case ACT_RXTX:
					if (gses->win->prev->handler == cwwindow_func){
						return 1;
					}
					rxtx();
					return 0;
					break;    
#ifdef HAVE_HAMLIB
				case ACT_TOGGLE_SPLIT_VFO:
					trigs_toggle_split_vfo(gtrigs);
					break;
#endif

#if defined (Z_HAVE_SDL) && defined(Z_HAVE_LIBPNG)            
				case ACT_SCREENSHOT:
					sdl_screenshot(0);
					break;
            
				case ACT_WINDOWSHOT:
					sdl_screenshot(1);
					break;
#endif
            
			}
			break;

		case EV_MOUSE:
            /*if (ev->b == B_MOVE) break;
			dbg("preferred_func MOUSE: b=%d\n", ev->b);
			if (ev->b == (B_DRAG | B_LEFT)){
				int p = -1;
				if (gses->sel_start < 0){
					gses->sel_start = ev->x + ev->y * term->x;
                }else{
				    gses->sel_min = Z_MIN(gses->sel_min, gses->sel_start);
                    gses->sel_max = Z_MAX(gses->sel_max, gses->sel_stop);
					p = ev->x + ev->y * term->x;
					if (p <= gses->sel_start)
						gses->sel_start = p;
					else
						gses->sel_stop = p;
				}
				gses->sel_min = Z_MIN(gses->sel_min, gses->sel_start);
                gses->sel_max = Z_MAX(gses->sel_max, gses->sel_stop);
				dbg("p=%d  sel=%d %d, minmax=%d %d\n", p, gses->sel_start, gses->sel_stop, gses->sel_min, gses->sel_max);
				term->dirty = 1;
				redraw_later();
			}else if (ev->b == (B_LEFT | B_UP)){
				dbg("up  sel=%d %d\n", gses->sel_start, gses->sel_stop);
                if (gses->sel_start > 0 && gses->sel_stop > 0){
                    dbg("copy\n");
                    gses->sel_start = -1;
                    gses->sel_stop = -1;
                }
            }else if ((ev->b == B_LEFT) == 0){
                dbg("clear\n");
				gses->sel_min = gses->sel_start;
				gses->sel_max = gses->sel_stop;
	            gses->sel_start = -1;
            	gses->sel_stop = -1;
				term->dirty = 1;
				redraw_later();
            }	  */
			break;
	}
	return 1;
}



static void compute_qrv_wkd(char *c){
	char *qrv_str;
	struct qrv_item *qi;
	if (!aband) return;
	
    CONDGFREE(aband->qrv_str);
    qrv_str=find_qrv_str_by_call(cw, c);
    if (qrv_str){
        aband->qrv_str = g_strdup(qrv_str);
    }

    CONDGFREE(aband->wkd_str);
    qi = qrv_get(qrv, c);
    if (qi){
        aband->wkd_str = g_strdup_printf("wkd %dx", qi->wkd[tolower(aband->bandchar) - 'a']);
    }

}

int confirm_call(void){
	char *oldtmpqcall, *c;

	if (!ctest || !aband) return 1;
    oldtmpqcall = TMPQ.callsign;
    c = TMPQ.callsign;
    if (!c) return 1;
    if (TMPQ.ucallsign) return 1;
    
	compute_qrv_wkd(z_str_uc(c));
                
	struct qso *dupe = stats_get_dupe(aband->stats, c, TMPQ.locator, ctest->phase, gses->mode);
    if (dupe != NULL){
		aband->dupe_qso = dupe;
        redraw_terminal(NULL);
		compute_qrv_wkd(c);
        duplicate_callsign(dupe);
        return 1;
    }
    add_tmpxchg(aband, aband->tmpqsos[0].callsign);
    after_callsign(aband, TMPQ.callsign, oldtmpqcall);
    aband->tmpqsos[0].ucallsign = 1;
    CLEAR_TMPQSO_STRING_UU(aband, callsign, ucallsign);
    wkd_tmpqso(aband, WT_CALLSIGN, c);
#ifdef HAVE_SNDFILE
	gssbd->code++;
#endif
    redraw_later();
	return 0;
}

int confirm_exc(void){

	if (!ctest || !aband) return 1;
    if (!aband->tmpqsos[0].exc) return 0;
    if (strlen(aband->tmpqsos[0].exc)==0) return 0;

    add_tmpxchg(aband, aband->tmpqsos[0].exc);
    after_exc(aband, TMPQ.exc);
                
    aband->tmpqsos[0].uexc = 1;
    CLEAR_TMPQSO_STRING_UU(aband, exc, uexc);
    wkd_tmpqso(aband, WT_EXC, TMPQ.exc);
#ifdef HAVE_SNDFILE
	gssbd->code++;
#endif
    redraw_later();
	return 0;
}

int confirm_wwl(void){
	if (!ctest || !aband) return 1;
    if (!aband->tmpqsos[0].locator) return 0;
    if (ctest->wwlused == 3 || ctest->wwlused == 4){ // 3=used(4), 4=opt(4)
        if (strlen(aband->tmpqsos[0].locator)<4) return 0;
    }else{
        if (strlen(aband->tmpqsos[0].locator)!=6) return 0;
    }

	if (TMPQ.callsign && !TMPQ.dupe){
		struct qso *dupe = stats_get_dupe(aband->stats, TMPQ.callsign, TMPQ.locator, ctest->phase, gses->mode);
		if (dupe != NULL){
			aband->dupe_qso = dupe;
			if (!aband->ignoreswap){
				aband->dupe_qso = dupe;
				compute_qrv_wkd(TMPQ.callsign);
				duplicate_callsign(dupe);
			}
			return 0;
		}
	}
    add_tmpxchg(aband, TMPQ.locator);
                
    aband->tmpqsos[0].ulocator = 1;
    aband->tmpqsos[0].uqrb = 1;
    aband->tmpqsos[0].uqtf = 1;
    after_locator(aband, TMPQ.locator);
    CLEAR_TMPQSO_STRING_UU(aband, locator, ulocator);
    CLEAR_TMPQSO_GDOUBLE_UU  (aband, qrb, uqrb);
    CLEAR_TMPQSO_QTF_UU   (aband);
    wkd_tmpqso(aband, WT_LOCATOR, TMPQ.locator);
    /*map_clear_qso(&aband->tmplocqso); */
#ifdef HAVE_SNDFILE
	gssbd->code++;
#endif
    redraw_later();
	return 0;
}
void clear_tmpqsos_inputline(void){
    if (!ctest || !aband) {  /* HACK F3 */
        menu_contest_open(NULL);
        return;
    }
    if (aband->readonly) return;
    clear_tmpqsos(aband,1);
    add_swap(aband, "CLR");
    clear_inputline(aband->il);
    get_cw_qs(aband->il->cdata); /* clears */ 
    get_band_qs(aband, aband->il->cdata);
    get_oband_qs(aband, aband->il->cdata);
    get_hf_dxc(aband->il->cdata);
    send_inputline(aband);
    map_clear_qso(&aband->tmplocqso, aband);
	ac_track(gacs, NULL, -1);
    redraw_later();
}
    
void send_event(struct event *ev)
{
//    struct qso *qso;
//    gchar *c;
//  gchar *qrv_str;
    int i;
//    char *oldtmpqcall = NULL;
//    struct qrv_item *qi;

    if (!gses) return;
    //dbg("send_event ev=%d, x=%d, y=%d, b=%d\n",ev->ev,ev->x,ev->y ,ev->b);
    if (ev->ev == EV_KBD) {
        if (gses->ontop && gses->focused){
            if (sw_focus_func(ev,1)) return;
        }else{
            switch (kbd_action(KM_MAIN, ev)) {
                case ACT_SCROLL_LEFT:
                    if (glog->ho>0) glog->ho--;
                    redraw_later();
                    goto x;
                case ACT_SCROLL_RIGHT:
                    if (glog->ho<70) glog->ho++;
                    redraw_later();
                    goto x;
                default:
                    if (!inputln_func(INPUTLN(aband), ev)) break;
                    /*dbg("inputln_func\n");*/
                    if (ev->x!=KBD_LEFT &&
                        ev->x!=KBD_RIGHT &&
                        ev->x!=KBD_HOME &&
                        ev->x!=KBD_END){    

                        char *qsstr;
                        if (aband){
                            qsstr=strrchr(aband->il->cdata, ' ');
                            if (!qsstr) qsstr=aband->il->cdata;
                            else qsstr++;
                        }else{
                            qsstr=strrchr(gses->il->cdata, ' ');
                            if (!qsstr) qsstr=gses->il->cdata;
                            else qsstr++;
                        }
                        
                        if (aband){
                            get_band_qs(aband, qsstr);
                            get_oband_qs(aband, qsstr);
                        }
                        get_cw_qs(qsstr);
                        //FIXME get_hf_dxc(qsstr);
                        send_inputline(aband);
                        
                        redraw_later();
                    }
                    return;
                
            }
        }
//    dbg("send_event2 %d,%d,%d,%d\n",ev->ev,ev->x,ev->y ,ev->b);
        
        switch (kbd_action(KM_MAIN, ev)) {
            case ACT_MENU:
                activate_bfu_technology(-1);
                goto x;
            case ACT_FILE_MENU:
                activate_bfu_technology(0);
                goto x;
            case ACT_REALLYQUIT:
                exit_prog(GINT_TO_POINTER(1));
                goto x;
            case ACT_QUIT:
                exit_prog(GINT_TO_POINTER(ev->x == KBD_CTRL_C));
                goto x;
            case ACT_NEXT_SUBWIN:
 /*               dbg("send_event: next subwin\n");*/
                sw_totop_next(1, 0);
                if (gses->focused){
                    sw_set_focus();
                    il_unset_focus(INPUTLN(aband));
                }else{
                    sw_unset_focus();
                    il_set_focus(INPUTLN(aband));
                }
                redraw_later();
                goto x;    
            case ACT_PREV_SUBWIN:
 /*               dbg("send_event: next subwin\n");*/
                sw_totop_next(-1, 0);
                if (gses->focused){
                    sw_set_focus();
                    il_unset_focus(INPUTLN(aband));
                }else{
                    sw_unset_focus();
                    il_set_focus(INPUTLN(aband));
                }
                redraw_later();
                goto x;    
            case ACT_UP:
/*                dbg("send_event: focus\n");*/
/*                if (!ctest || !aband) goto x; */
                if (gses->ontop->type!=SWT_QSOS || 
                    (aband && aband->qsos->len) || 
                    (ctest && gses->ontop->allqsos && ctest->allqsos->len)){
                    /*dbg("focusing...\n"); */
					if (gses->ontop->type == SWT_QSOS && aband){ 
                        struct subwin *sw = gses->ontop;
						gses->ontop->cur = QSOS_LEN;
					    //gses->ontop->check_bounds(gses->ontop);
					} 
                    il_unset_focus(INPUTLN(aband));
                    sw_set_focus();
                    redraw_later();
                }
                goto x;

            case ACT_ESC:
            case ACT_RX:
                /*dbg("send_event: esc\n");*/
                esc();
                goto x;    
                
            case ACT_RXTX:
			case ACT_TOGGLE_SPLIT_VFO:
                preferred_func(ev);
                break;    
                
            case ACT_MODE:
                gses->tx = 0;
                /*cwdaemon_abort(cwda);*/
                cq_abort(0);
                peer_tx(aband, 0);
                if (get_mode() == MOD_CW_CW) {
                    set_mode(MOD_SSB_SSB);
                    if (!ctest){
                        default_rst_to_tmpqsos(aband);
                        redraw_later();
                        break;
                    }
                    if (strcmp(cfg->default_rst, TMPQ.rsts)==0){
                        default_rst_to_tmpqsos(aband);
                    }else{
                        zg_free0(aband->tmpqsos[1].rsts);
                        aband->tmpqsos[1].rsts=g_strdup("SSB");
                    }
                    redraw_later();
                    break;
                }
                if (get_mode() == MOD_SSB_SSB){
                    set_mode(MOD_CW_CW);
                    if (!ctest){
                        default_rst_to_tmpqsos(aband);
                        redraw_later();
                        break;
                    }
                    if (strcmp(cfg->default_rs, TMPQ.rsts)==0){
                        default_rst_to_tmpqsos(aband);
                    }else{
                        zg_free0(aband->tmpqsos[1].rsts);
                        aband->tmpqsos[1].rsts=g_strdup("CW");
                    }
                    redraw_later();
                    break;
                }
				break;
            case ACT_CQ_0:
                if (can_cq(aband)) cq_run_by_number(0);
                break;
            case ACT_CQ_1:
                if (can_cq(aband)) cq_run_by_number(1);
                break;
            case ACT_CQ_2:
                if (can_cq(aband)) cq_run_by_number(2);
                break;
            case ACT_CQ_3:
                if (can_cq(aband)) cq_run_by_number(3);
                break;
            case ACT_CQ_4:
                if (can_cq(aband)) cq_run_by_number(4);
                break;
            case ACT_CQ_5:
                if (can_cq(aband)) cq_run_by_number(5);
                break;
            case ACT_PAGE_UP:
                cwdaemon_qrq(cwda, 2);
                redraw_later();
                break;
            case ACT_PAGE_DOWN:
                cwdaemon_qrs(cwda, 2);
                redraw_later();
                break;  

            case ACT_CLEAR_TMPQSOS:
/*                dbg("clear_tmpqsos\n");*/
                if (!ctest || !aband || aband->readonly) goto x;
                clear_tmpqsos(aband, 1);
                add_swap(aband, "CLR");
                map_clear_qso(&aband->tmplocqso, aband);
                redraw_later();
                goto x;
                
            case ACT_CLEAR_TMPQSOS_INPUTLINE:
                clear_tmpqsos_inputline();
                goto x;
                
            case ACT_CONFIRM_CALL:
                if (confirm_call()) goto x;
                break;
            case ACT_CONFIRM_EXC:
				if (confirm_exc()) goto x;
                break;
            case ACT_CONFIRM_WWL:
                if (confirm_wwl()) goto x;
                break;
            case ACT_SWAP_CALL:
                if (!ctest || !aband) goto x;
                if (aband->tmpqsos[0].callsign && aband->tmpqsos[1].callsign){
                    int susp;
                    gchar *c;

                    c = aband->tmpqsos[0].callsign;
                    aband->tmpqsos[0].callsign = aband->tmpqsos[1].callsign;
                    aband->tmpqsos[1].callsign = c;

					c = aband->tmpqsos[0].name;
                    aband->tmpqsos[0].name = aband->tmpqsos[1].name;
                    aband->tmpqsos[1].name = c;

                    add_tmpxchg(aband, aband->tmpqsos[0].callsign);
                    if ((susp=get_susp_call(cw, dw, aband->tmpqsos[0].callsign, aband->tmpqsos[0].locator))!=0){
                        aband->tmpqsos[0].suspcallsign = susp;
                    }else{
                        aband->tmpqsos[0].suspcallsign = 0;
                        aband->tmpqsos[0].susplocator = 0;
                    }
                    wkd_tmpqso(aband, WT_CALLSIGN, TMPQ.callsign);
#ifdef HAVE_SNDFILE
					gssbd->code++;
#endif
					update_susp(aband);
					redraw_later();
                }
                break;
                
            case ACT_SWAP_WWL:
                if (!ctest || !aband) goto x;
                if (aband->tmpqsos[0].locator && aband->tmpqsos[1].locator){
                    int susp;
                    gchar *c;
                    gdouble qrb;
                    gint qtf;

                    map_clear_qso(&aband->tmplocqso, aband);
                    c = aband->tmpqsos[0].locator;
                    aband->tmpqsos[0].locator = aband->tmpqsos[1].locator;
                    aband->tmpqsos[1].locator = c;
                    add_tmpxchg(aband, aband->tmpqsos[0].locator);

                    qrb = aband->tmpqsos[0].qrb;
                    aband->tmpqsos[0].qrb = aband->tmpqsos[1].qrb;
                    aband->tmpqsos[1].qrb = qrb;

                    qtf = aband->tmpqsos[0].qtf;
                    aband->tmpqsos[0].qtf = aband->tmpqsos[1].qtf;
                    aband->tmpqsos[1].qtf = qtf;
                    if ((susp=get_susp(cw, dw, aband->tmpqsos[0].callsign, aband->tmpqsos[0].locator, 1))!=0){
                        aband->tmpqsos[0].susplocator = susp & 0xff;
                        aband->tmpqsos[0].suspcallsign = susp >> 8;
                    }else{
                        aband->tmpqsos[0].susplocator = 0;
                        aband->tmpqsos[0].suspcallsign = 0;
                    }

                    wkd_tmpqso(aband, WT_LOCATOR, TMPQ.locator);
                    
                    zg_free0(aband->tmplocqso.locator);
                    aband->tmplocqso.locator=g_strdup(TMPQ.locator);
                    compute_qrbqtf(&aband->tmplocqso);
                    map_add_qso(&aband->tmplocqso, aband);
#ifdef HAVE_SNDFILE
					gssbd->code++;
#endif
					update_susp(aband);
					redraw_later();
                }
                break;    
            case ACT_SAVE_ALL:
                save_all_bands_txt(0);
                break;
            case ACT_CHOP:
                if (!ctest) break;
                menu_chop(NULL);
                break;
            case ACT_CALLINFO:
                call_info(NULL);
                break;
            case ACT_SKED:
                if (!ctest || !aband) break;
                if ((!TMPQ.callsign || !strlen(TMPQ.callsign)) && aband->qsos->len>0){
                    sked_from_qso((struct qso *)g_ptr_array_index(aband->qsos, aband->qsos->len-1));
                }else{
                    sked_from_tmpqso(&(aband->tmpqsos[0]));
                }
                break;
            case ACT_SKED_QRG:
                if (!ctest) break;
                menu_skedqrg(NULL);
                break;
            case ACT_UNFINISHED:

                if (!ctest || !aband) break;
                if (!TMPQ.callsign && !TMPQ.locator) break;
             
                menu_unfinished(NULL);
                goto x;
            case ACT_PLAY_LAST:
                if (gses->focused) break;
#if defined(HAVE_SNDFILE)
                ssbd_play_last_sample(gssbd, NULL);
//                player_play("/home/ja/tucnak/cq/OK1ZIA_OK1ZIA.wav");
#endif
                break;
            case ACT_SEEK_A:
				ac_track(gacs, NULL, -10);
				if (!ctest || !aband) goto x;
                if (TMPQ.locator)
                    rot_seek(get_rotar(0), TMPQ.qtf, -90);
                break;
                
            case ACT_SEEK_B:
				ac_track(gacs, NULL, -10);
				if (!ctest || !aband) goto x;
                if (TMPQ.locator)
                    rot_seek(get_rotar(1), TMPQ.qtf, -90);
                break;

            /*case ACT_GRAB_BAND:
                menu_grabband(NULL);
                break;*/

            case ACT_ROTAR:
                menu_rotar(NULL);
                break;

			case ACT_ROTAR_STOP:
				rotars_stop();
				break;

			case ACT_RUNMODE:
				if (!ctest) break;
				runmode(!ctest->runmode);
				redraw_later();
				break;

            case ACT_TUNE:
                if (get_mode() != MOD_CW_CW) break;
                gses->tune++;
                if (gses->tune == 3) gses->tune = 0;
                cwdaemon_tune(cwda, gses->tune);
                break; 
            
            case ACT_AC_CQ:
                ac_cq();
                break;

#ifdef Z_HAVE_SDL
			case ACT_ZOOMIN:
				tsdl_change_font('+');
				break;
			case ACT_ZOOMOUT:
				tsdl_change_font('-');
				break;

			case ACT_ZOOM0:
				if (cfg->fontheight == 16) break;
				cfg->fontheight = 16;
				sdl_setvideomode(sdl->screen->w, sdl->screen->h, 0);
				resize_terminal(NULL);
#ifdef AUTOSAVE
                menu_save_rc(NULL);
#endif
				break;
			case ACT_FULLSCREEN:
				cfg->fullscreen = !cfg->fullscreen;
#ifdef Z_HAVE_SDL1
				sdl_setvideomode(sdl->window_w, sdl->window_h, 0);
#endif
#ifdef Z_HAVE_SDL2
				SDL_SetWindowFullscreen(zsdl->window, cfg->fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
#endif
				resize_terminal(NULL);
#ifdef AUTOSAVE
                menu_save_rc(NULL);
#endif
                break;
			case ACT_MAXIMIZE:
				zsdl_maximize(zsdl, 2);
				break;
			case ACT_AC_INFO:
				g_free(gses->callunder);
				if (!aband) break;
				gses->callunder = g_strdup(TMPQ.callsign);
				if (!gses->callunder || !*gses->callunder) break;
				fifo_kst_ac_info(TMPQ.locator, NULL);
				break;
#endif
                
			case ACT_OPEN_NET:
				if (ctest) break;
				menu_discover_peers3(open_from_net3, NULL);
				break;

            default:
                /*if (ev->x == KBD_CTRL_C) goto quit;*/
                if (ev->y & KBD_ALT) {
                    struct window *m;

                    if (ev->x>='0' && ev->x<='9'){
                        int a = ev->x - '0';
                        
                        if (a==0) a=10;
                        if (sw_set_ontop(a-1, 0)){
                            if (!gses->focused/* ||
                                (gses->ontop && gses->ontop->type == SWT_QSOS)*/){
                                sw_unset_focus();
                                il_set_focus(INPUTLN(aband));
                            }else{
                                sw_set_focus();
                                il_unset_focus(INPUTLN(aband));
                            }
                            redraw_later();
                        }
                        goto x;                       
                    }
#if 0                    
                    if (ctest && z_char_uc(ev->x)=='L'){
/*                        printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
                        g_thXXXXread_create(delay_func, NULL, TRUE, NULL);  */
                        log_adds("---dump request---");
                        trace(cfg->trace_qsos, "---dump request---");
                        dump_all_sources(ctest);
                    }
#endif                            

                    
                    ev->y &= ~KBD_ALT;
                    activate_bfu_technology(-1);
                    m = term->windows.next;
                    m->handler(m, ev, 0);
                    if (term->windows.next == m) {
                        delete_window(m);
                    } else goto x;
                
                    ev->y &= ~KBD_ALT;
                }

                if (ev->y & KBD_CTRL){
                    char bandchar;
                    struct band *b;
                    
                    if (ev->x>='0' && ev->x<='9'){
                        int a = ev->x - '0';
                        
                       /* if (a==0) a=10; Ctrl+0 means subwin 10  */ 
                        a+=10;
                        if (sw_set_ontop(a-1, 0)){
                            if (!gses->focused /*||
                                (gses->ontop && gses->ontop->type == SWT_QSOS)*/){
                                sw_unset_focus();
                                il_set_focus(INPUTLN(aband));
                            }else{
                                sw_set_focus();
                                il_unset_focus(INPUTLN(aband));
                            }
                            redraw_later();
                        }
                        goto x;                       
                    }

                    if (!ctest || !aband) goto x;
                    bandchar=z_char_lc((char)ev->x);
                    b=find_band_by_bandchar(bandchar);
                    activate_band(b);
                    break;
                }
            

        }
    }
   if (ev->ev == EV_MOUSE) {
        int y, hit = 0, spypeers;
/*        dbg("mouse event x=%d y=%d b=%d\n", ev->x, ev->y, ev->b); */
        /* menu */
        if (ev->y == 0 && (ev->b & BM_ACT) == B_DOWN) hit = 1;
		else if (cfg->usetouch && ev->y == 1 && (ev->b & BM_ACT) == B_DOWN) hit = 1;
		
		if (hit){
            struct window *m;
			ev->y = 0;
            activate_bfu_technology(-1);
            m = term->windows.next;
            m->handler(m, ev, 0);
            goto x;
        }
		/* locator */
#ifdef Z_ANDROID
		if ((ev->b & B_CLICK) && ev->y == 2 && ev->x >= 3 && ev->x < term->x-QSONR_WIDTH-BAND_WIDTH){
			zandroid_update_location();
			redraw_later();
		}
#endif
        /* input line */
        y = term->y - 1 - cfg->loglines;
		if (ctest && aband && !ctest->oldcontest) y -= ctest->spypeers->len;
		hit = 0;
        //if (ev->y==y && (ev->b & ~B_MOVE) !=0) hit = 1;
        if (ev->y==y && (ev->b & B_CLICK) !=0) hit = 1;
		else if (cfg->usetouch && (ev->y == y-1 || ev->y == y+1) && (ev->b & B_CLICK) !=0) hit = 1;
		if (hit){   
            struct inputln *il = INPUTLN(aband);
            //dbg("EV_MOUSE([%d,%d,%d,%d])\n",ev->ev,ev->x,ev->y,ev->b);
            sw_unset_focus();
            il_set_focus(il);
            if (ev->x >= il->x + il->l + 4){
                if (ev->x <= il->x + il->l + 2 + 8) {
                    clear_tmpqsos_inputline();
                }
            }else{
                inputln_func(il, ev);
            }
            redraw_later();
        }
    
        /* subwin tabs */
        if (gses && (ev->b & BM_ACT) == B_DOWN){
			int i;
            struct subwin *sw;
			
			if (cfg->splitheight > 0){
				if (ev->y == QSONR_HEIGHT - 1){
					for (i=0; i<gses->subwins->len; i++){
						sw = (struct subwin*)g_ptr_array_index( gses->subwins, i);
						if (ev->x >= sw->titl1 && ev->x <= sw->titl2){
							sw_set_ontop(i, 1);

							redraw_later();
							break;
						}
					}
				}
				if (ev->y == gses->y1 - 1){
					for (i=0; i<gses->subwins->len; i++){
						sw = (struct subwin*)g_ptr_array_index( gses->subwins, i);
						if (ev->x >= sw->titl1 && ev->x <= sw->titl2){
							sw_set_ontop(i, 0);
							redraw_later();
							break;
						}
					}
				} 
			}else{
				hit = 0;
				if (ev->y == QSONR_HEIGHT - 1) hit = 1;
				else if (cfg->usetouch && ev->y == QSONR_HEIGHT - 2) hit = 1;
				if (hit){
                    //dbg("mouse: x=%d y=%d\n", ev->x, ev->y);
					for (i=0; i<gses->subwins->len; i++){
						sw = (struct subwin*)g_ptr_array_index( gses->subwins, i);
						if (ev->x >= sw->titl1 && ev->x <= sw->titl2){
							if (sw_set_ontop(i, 0)){
								if (!gses->focused /*||
									(gses->ontop && gses->ontop->type == SWT_QSOS)*/){
									sw_unset_focus();
									il_set_focus(INPUTLN(aband));
								}else{
									sw_set_focus();
									il_unset_focus(INPUTLN(aband));
								}
							}
                            redraw_later();
							break;
                        }
					}
				}
			}
        }
        if (gses && ev->b == B_RIGHT && ev->y == QSONR_HEIGHT - 1){
			set_window_ptr(gses->win, gses->ontop->titl1, ev->y + 1);
			subwins_menu(send_event);
		}
		/* confirm call/loc */
		spypeers = 0;
		if (ctest && !ctest->oldcontest) spypeers = ctest->spypeers->len;

		if (ev->b == B_LEFT && ev->x >= 0 && ev->x < 76){ // preselect before entering loop
			for (i = -1; i <= DISP_QSOS; i++){
				int cfmy;
				cfmy = term->y - cfg->loglines - spypeers - DISP_QSOS + i - 1;
				if (ev->y != cfmy) continue;
				if (ev->x >= 18 && ev->x < 32){
					confirm_call();
					goto x;
				}
				if (ev->x >=50 && ev->x < 55){
					confirm_exc();
					goto x;
				}
				if (ev->x >=55 && ev->x <= 60){
					confirm_wwl();
					goto x;
				}
			}
		}

		/* context menu call */
		if (ev->b == B_RIGHT && ev->x >= 18 && ev->x < 32){ 
			for (i = -1; i <= DISP_QSOS; i++){
				int cfmy;
				cfmy = term->y - cfg->loglines - spypeers - DISP_QSOS + i - 1;
				if (ev->y != cfmy) continue;
				if (ev->x >= 18 && ev->x < 32){
					g_free(gses->callunder);
					gses->callunder = g_strdup(aband->tmpqsos[i].callsign);
					if (!gses->callunder) goto x;

					call_ctx_menu(ev->x, ev->y);
					goto x;
				}
			}
		}
            
        /* subwin */
        if (gses && 
			ev->y >= gses->ontop->y && 
            ev->y < gses->ontop->y+gses->ontop->hh){
            
            sw_default_func(gses->ontop,ev,1);
        }

		/* glog */
		if (ev->b == B_RIGHT){
			if (gses && ev->y >= term->y - cfg->loglines){
				g_free(gses->callunder);
				int y2 = ev->y - term->y + cfg->loglines;
				gses->callunder = fifo_call_under(glog, ev->x, y2);
				if (!gses->callunder) return;

				call_ctx_menu(ev->x, ev->y);
			}
		}
    }
    x:;
    return;
}

void call_ctx_menu(int evx, int evy){
	int items = 0;
	struct menu_item *mi = NULL;
	int y = evy - term->y + cfg->loglines;
	mi = new_menu(1);
	mi->rtext = gses->callunder;
	add_to_menu(&mi, CTEXT(T_MESSAGE), "", CTEXT(T_HK_MESSAGE), fifo_message, NULL, 0); items++;
	add_to_menu(&mi, CTEXT(T_INFO), "", CTEXT(T_HK_INFO), fifo_kst_info, NULL, 0); items++;
#ifdef Z_HAVE_SDL
	if (gacs) { add_to_menu(&mi, CTEXT(T_AC_INFO), "", CTEXT(T_HK_AC_INFO), fifo_kst_ac_info, NULL, 0); items++; }
#endif
	y = evy - 1;
	if (cfg->usetouch) y = evy - items - 1;
	set_window_ptr(gses->win, evx - 3, y);
	do_menu(mi, NULL);
}



void draw_root_window(){
    gchar *c;                       
    int i, a, y;
    char dtime[6];
    char s[1000], ss[500];
    int spypeers=0;
    struct rotar *rot;
    char degree;
	char exc[MAX_EXC_LEN+1];
    struct inputln *il;

    degree=' ';
#if defined(Z_HAVE_SDL) && !defined(Z_ANDROID)     
    //if (sdl) degree='°';
    if (sdl) degree=0xb0;
#endif
    
   /* dbg("draw_root_window\n");*/

    fill_area(0,0,term->x,term->y,COL_BG);
    if (ctest && ctest->tname && *ctest->tname){
        char s[256];
        strcpy(s,"  Tucnak "VERSION_STRING);
        print_text(1,0,-1,ctest->tname,COL_NORM);
        print_text(term->x-QSONR_WIDTH-strlen(s)-2,0,-1,s,COL_NORM);
    }else{
        print_text(0,0,-1,"\xadMenu   The ultimate contestlog - necessary as known  ver. "VERSION,COL_NORM);
    }

    log_draw(glog);
	if (ctest && !ctest->oldcontest) spypeers=ctest->spypeers->len;

    draw_frame(0,ORIG_Y,term->x-QSONR_WIDTH-BAND_WIDTH,3,COL_NORM,1);
    draw_frame(0,ORIG_Y+2,term->x-QSONR_WIDTH-BAND_WIDTH,4,COL_NORM,1);
    draw_frame(term->x-QSONR_WIDTH-BAND_WIDTH-1,ORIG_Y,BAND_WIDTH+1,QSONR_HEIGHT-1,COL_NORM,1);
    draw_frame(term->x-QSONR_WIDTH-1,0,QSONR_WIDTH+1,QSONR_HEIGHT,COL_NORM,1);
    
    draw_frame(0,QSONR_HEIGHT-1,term->x,term->y-QSONR_HEIGHT-2-cfg->loglines-spypeers,COL_NORM,1);
    
#ifdef HAVE_SNDFILE
	if (gses && gssbd && gses->icon == gssbd->recicon && term->last_screen != NULL){
        int x, y;
        x=term->x-1;
        for (y=0;y<6;y++) {
            term->last_screen[x+term->x*y]=0;
//            set_char(x, y, '1' + COL_NORM);
//            term->screen[x+term->x*y]='1';
        }
//		dbg(" gses->volume ");
    }
#endif


    set_only_char(term->x-QSONR_WIDTH-BAND_WIDTH-1,ORIG_Y,FRAME_RDL);
    set_only_char(term->x-QSONR_WIDTH-1,ORIG_Y,FRAME_UDL);
    set_only_char(0,ORIG_Y+2,FRAME_URD);
    set_only_char(term->x-QSONR_WIDTH-BAND_WIDTH-1,ORIG_Y+2,FRAME_UDL);
    set_only_char(0,QSONR_HEIGHT-1,FRAME_URD);
    set_only_char(term->x-QSONR_WIDTH-1,QSONR_HEIGHT-1,FRAME_URL);
    set_only_char(term->x-QSONR_WIDTH-BAND_WIDTH-1,QSONR_HEIGHT-1,FRAME_URL);
    set_only_char(term->x-1,QSONR_HEIGHT-1,FRAME_UDL);
	if (cfg->splitheight > 0){
		y = gses->y1 - 1;
		set_only_char(0, y, FRAME_URD);
		for (i = 1; i < term->x - 1; i++) set_only_char(i, y, FRAME_RL);
		set_only_char(term->x - 1, y, FRAME_UDL);
	}

    print_text(11,term->y-ORIG_Y-2-cfg->loglines-spypeers-1,-1,VTEXT(T_SES_QTR),COL_NORM);
    print_text(19,term->y-ORIG_Y-2-cfg->loglines-spypeers-1,-1,VTEXT(T_SES_QRA),COL_NORM);
    print_text(31,term->y-ORIG_Y-2-cfg->loglines-spypeers-1,-1,VTEXT(T_SES_RST),COL_NORM);
    if (ctest && ctest->excused>0) print_text(49,term->y-ORIG_Y-2-cfg->loglines-spypeers-1,-1,VTEXT(T_SES_EXC),COL_NORM);
    if (ctest && ctest->wwlused>0) print_text(54,term->y-ORIG_Y-2-cfg->loglines-spypeers-1,-1,VTEXT(T_SES_QTH),COL_NORM);
    print_text(62,term->y-ORIG_Y-2-cfg->loglines-spypeers-1,-1,VTEXT(T_SES_QRB),COL_NORM);
    print_text(74,term->y-ORIG_Y-2-cfg->loglines-spypeers-1,-1,VTEXT(T_SES_FLG),COL_NORM);
    print_text(80,term->y-ORIG_Y-2-cfg->loglines-spypeers-1,-1,VTEXT(T_SES_OPE),COL_NORM);
    print_text(88,term->y-ORIG_Y-2-cfg->loglines-spypeers-1,-1,VTEXT(T_SES_REM),COL_NORM);

    if (can_cq(aband)){
        if (gses && gses->last_cq && gses->last_cq->mode!=MOD_NONE){
            if (gses->last_cq->mode==MOD_CW_CW)
                sprintf(s, " CW%d", gses->last_cq->nr);
            else
                sprintf(s, "SSB%d", gses->last_cq->nr);
        }else{    
            if (gses->tx)
                strcpy(s, "  TX");
            else
                strcpy(s, "  rx");
        }
    }else{
        strcpy(s, "LOCK");
    }
    print_text(15,term->y-1-cfg->loglines-spypeers,-1,s,COL_NORM);
        
    if (cwda){
		char *run = "";
		if (ctest) run = ctest->runmode ? "Run" : "S&P";
        c = g_strdup_printf(VTEXT(T_SES_WPM), cwda->speed, cwda->weight, run);
        print_text(term->x-QSONR_WIDTH-BAND_WIDTH,ORIG_Y+1,BAND_WIDTH-1, c, COL_NORM); 
        g_free(c);
    }

    rot=get_rotar(0);
    if (rot
#ifdef OCT8TOR
		&& !rot->oct_hidden
#endif
		){
		if (rot->desc && *rot->desc)
			g_strlcpy(ss, rot->desc, 8+1);
		else
			strcpy(ss, "RotA");
        sprintf(s,"%8s: %3d%c%+d%c",ss, rot->qtf, degree, rot->elev, degree); 
        print_text(term->x-QSONR_WIDTH-BAND_WIDTH,ORIG_Y+2,BAND_WIDTH-1, s, COL_NORM); 
    }
    rot=get_rotar(1);
    if (rot
#ifdef OCT8TOR
		&& !rot->oct_hidden
#endif
		){
		if (rot->desc && *rot->desc)
			g_strlcpy(ss, rot->desc, 8+1);
		else
			strcpy(ss, "RotB");
        sprintf(s,"%8s: %3d%c%+d%c",ss, rot->qtf, degree, rot->elev, degree); 
        print_text(term->x-QSONR_WIDTH-BAND_WIDTH,ORIG_Y+3,BAND_WIDTH-1, s, COL_NORM); 
    }
    
#ifdef HAVE_HAMLIB
    //gtrigs->qrg = 10368120000.0;
    if (gtrigs != NULL && gtrigs->trigs->len > 0 /*&& trig->thread*/){
        if (gtrigs->rigerr == RIG_OK){
			z_qrg_format(s, sizeof(s), gtrigs->qrg); 
            
            if (gtrigs->rit >= 100) 
                strcat(s, "+");
            else 
                if (gtrigs->rit <= -100) strcat(s, "-");
            else
                strcat(s, " "); 
#ifdef Z_HAVE_SDL
			if (sdl && rotars->len < 2)
            {
			   	print_text(term->x-QSONR_WIDTH-BAND_WIDTH+18-strlen(s),ORIG_Y+4-1,BAND_WIDTH-1, s, COL_NORM | (DOUBLEHT_MASK << 15)); // to redraw also upper line
			   	print_text(term->x-QSONR_WIDTH-BAND_WIDTH+18-strlen(s),ORIG_Y+4,BAND_WIDTH-1, s, COL_NORM | (DOUBLEHB_MASK << 15)); 
			}
            else
#endif                
            {
			  	print_text(term->x-QSONR_WIDTH-BAND_WIDTH+18-strlen(s),ORIG_Y+4,BAND_WIDTH-1, s, COL_NORM); 
			}
        }else{
			/*struct trig *trig = (struct trig *)g_ptr_array_index(gtrigs->trigs, 0);
            enum rig_errcode_e error; // thread
			error = (enum rig_errcode_e)trig->rigerr;
            if (error != RIG_OK) print_text(term->x-QSONR_WIDTH-BAND_WIDTH,ORIG_Y+4,BAND_WIDTH-1, trig_short_errstr(error), COL_NORM); */
            if (gtrigs->rigerr != RIG_OK) print_text(term->x-QSONR_WIDTH-BAND_WIDTH,ORIG_Y+4,BAND_WIDTH-1, trig_short_errstr((enum rig_errcode_e)gtrigs->rigerr), COL_NORM); 
        }
    }else{
        if (gtrigs != NULL && gtrigs->rigerr != RIG_OK) print_text(term->x-QSONR_WIDTH-BAND_WIDTH,ORIG_Y+4,BAND_WIDTH-1, trig_short_errstr((enum rig_errcode_e)gtrigs->rigerr), COL_INV); 
    }
    
#endif

    if (aband){

        if (aband->ctrlstate==CTRL_REQR){
            print_text(19,term->y-ORIG_Y-2-cfg->loglines-spypeers-1,-1, VTEXT(T_QSO_REQ_FROM_SP), COL_INV);
        }
        if (aband->ctrlstate==CTRL_REQS){
            print_text(19,term->y-ORIG_Y-2-cfg->loglines-spypeers-1,-1, VTEXT(T_QSO_REQ_SENT), COL_INV);
        }
        if (aband->ctrlstate==CTRL_RUNNING){
            print_text(19,term->y-ORIG_Y-2-cfg->loglines-spypeers-1,-1,VTEXT(T_GO),COL_INV);
        }
    
        g_snprintf(s, 98, " %s %s (%s) ", ctest->pcall, ctest->pwwlo, aband->operator_);
        z_str_uc(s);
        print_text(4,ORIG_Y,97,s,COL_NORM);
        
        //if (ctest->total_method == 3)
        if (ctest->qsoglob)
            draw_bigdigit(term->x-20+2,1,ctest->allqsos->len+1);
            //draw_bigdigit(term->x-20+2,1,ctest->allb_nqsos+1);
        else
            draw_bigdigit(term->x-20+2,1,aband->qsos->len+1);
        redraw_stats(aband);

        c=g_strconcat(aband->bandname,":", NULL);
#ifdef Z_HAVE_SDL
		if (sdl && !aband->unres && !aband->tmpqsos[1].date_str && !aband->tmpqsos[1].time_str)
        {
            print_text(14-strlen(c),term->y-2-cfg->loglines-spypeers,-1,c,COL_NORM | (DOUBLEHT_MASK << 15));
            print_text(14-strlen(c),term->y-1-cfg->loglines-spypeers,-1,c,COL_NORM | (DOUBLEHB_MASK << 15));
        }
        else
#endif
        {
            print_text(14-strlen(c),term->y-1-cfg->loglines-spypeers,-1,c,COL_NORM);
        }
        g_free(c);
        
        

        for (i=0;i<spypeers;i++){
            struct spypeer *sp;
            char s[3];
            
            sp=(struct spypeer *)g_ptr_array_index(ctest->spypeers, i);
			if (sp == NULL) continue; // OZ1CT crash

            s[0]=sp->abandchar != '\0' ? toupper(sp->abandchar) : sp->bandchar;
            s[1]=':';
            s[2]='\0';
            print_text(0,term->y-cfg->loglines-spypeers+i,-1,s,COL_NORM);
            c=sp->operator_;
            if (c) print_text(2,term->y-cfg->loglines-spypeers+i,-1,c,COL_NORM);
            
            strcpy(s,"");
            if (sp->peertx==0) strcpy(s, "rx");
            if (sp->peertx==1) strcpy(s, "tx");
            if (sp->peertx==2) strcpy(s, "cq");
            print_text(15,term->y-cfg->loglines-spypeers+i,-1,s,COL_NORM);

            c=sp->callsign;
            if (c)  print_text(18,term->y-cfg->loglines-spypeers+i,-1,c,COL_NORM);
            c=sp->rsts;
            if (c) print_text(36-strlen(c),term->y-cfg->loglines-spypeers+i,-1,c,COL_NORM);
            c=sp->qsonrs;
            if (c) print_text(40-strlen(c),term->y-cfg->loglines-spypeers+i,-1,c,COL_NORM);
            c=sp->rstr;
            if (c) print_text(45-strlen(c),term->y-cfg->loglines-spypeers+i,-1,c,COL_NORM);
            c=sp->qsonrr;
            if (c) print_text(49-strlen(c),term->y-cfg->loglines-spypeers+i,-1,c,COL_NORM);
            if (sp->exc) {
                safe_strncpy0(exc, sp->exc, 11+1);
                print_text(50-strlen(exc),term->y-cfg->loglines-spypeers+i,-1,exc,COL_NORM);
            }
            c=sp->locator;
            if (c) print_text(55,term->y-cfg->loglines-spypeers+i,-1,c,COL_NORM);
            c=sp->inputline;
            if (c) print_text(62,term->y-cfg->loglines-spypeers+i,-1,c,COL_NORM);
            
        }
        
        if (aband->qrv_str){  // must show also for dupe
            int x, i, qy;

            x = 0;
            qy = term->y - cfg->loglines;
            c = g_strdup_printf(VTEXT(T_QRV_ON_S), "");
            fill_area(0, qy, term->x,1,COL_BG);
            print_text(0,qy, term->x, c,COL_NORM);
            x += strlen(c);
            g_free(c);
            for (i = 0; i < ctest->bands->len; i++){
                struct band *b;
                int color = COL_NORM;
                struct config_band *confb;

                b = (struct band*)g_ptr_array_index(ctest->bands, i);
                if (b == aband) continue;
                if (strchr(aband->qrv_str, z_char_lc(b->bandchar))) color = COL_DARKYELLOW;
                if (strchr(aband->qrv_str, z_char_uc(b->bandchar))) color = COL_YELLOW;

                confb = get_config_band_by_bandchar(b->bandchar);
                c = confb->adifband;
                if (b->qrg_min > 20000000) c = confb->cbrband;
                print_text(x, qy, -1, c, color);
                x += strlen(c) + 1;
            }
        }
        

        for (i=0;i<DISP_QSOS; i++){
            char s[100];
            if (i==0 && aband->dupe_qso != NULL){
				struct qso *q = aband->dupe_qso;
                
                print_text(3,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,q->date_str,COL_INV);
                dtime[0]=q->time_str[0]; dtime[1]=q->time_str[1]; dtime[2]=':';
                dtime[3]=q->time_str[2]; dtime[4]=q->time_str[3]; dtime[5]='\0';
                print_text(17-strlen(dtime),term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,dtime,COL_INV);
				stats_valid_key_display(s, q->callsign, q->locator, q->phase, q->mode);
                print_text(18,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1, s, COL_INV);
                print_text(36-strlen(q->rsts),term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,q->rsts,COL_INV);
                print_text(40-strlen(q->qsonrs),term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,q->qsonrs,COL_INV);
                print_text(45-strlen(q->rstr),term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,q->rstr,COL_INV);
                print_text(49-strlen(q->qsonrr),term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,q->qsonrr,COL_INV);
                print_text(55,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,q->locator,COL_INV);
                safe_strncpy0(exc, q->exc, 11+1);
                print_text(50,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,exc,COL_INV);
                if ((int)q->qrb<100000)
                    c=g_strdup_printf("%dkm",(int)q->qrb);
                else
                    c=g_strdup_printf("%d",(int)q->qrb);
                print_text(70-strlen(c),term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,c,COL_INV);
                g_free(c);
                if (q->qtf>=0) {
                    c=g_strdup_printf("%d%c",q->qtf, degree);
                    print_text(75-strlen(c),term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,c,COL_INV);
                    g_free(c);
                    /*c=g_strdup_printf("(%d)",((int)q->qtf+180)%360);
                    print_text(75,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,c,COL_INV);
                    g_free(c); */
                }
                print_text(81,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,q->operator_,COL_INV);
                print_text(89,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,q->remark,COL_INV);
                continue; /* don't draw normal QSO in line 0 */
            }

            c=aband->tmpqsos[i].date_str;
            if (c) print_text(3,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,c,COL_NORM);
               
            c=aband->tmpqsos[i].time_str;
            if (c) {
                dtime[0]=c[0]; dtime[1]=c[1]; dtime[2]=':';
                dtime[3]=c[2]; dtime[4]=c[3]; dtime[5]='\0';
                print_text(17-strlen(dtime),term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,dtime,COL_NORM);
            }
            
            
            c=aband->tmpqsos[i].callsign;
            if (c) {
                char *susp_c/*,*unkcall*/;
               
               /* if (aband->tmpqsos[i].unkcall) unkcall="n";
                else unkcall=" ";
                print_text(16,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,
                    unkcall, COL_NORM);  */
                
                switch (aband->tmpqsos[i].suspcallsign){
                    case 1:
                        susp_c="?";
                        break;
                    case 2:
                        susp_c="!";
                        break;    
                    default:
                        susp_c=" ";
                        break;
                }
                print_text(17,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,
                    susp_c, COL_RED);
                print_text(18,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,c,
                    aband->tmpqsos[i].ucallsign?COL_NORM:COL_INV);
                if (aband->tmpqsos[i].unkcall){
                        int x;
                        x=18+1+strlen(c);
                        print_text(x, term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,32-x,
                                VTEXT(T_NEW_CALL), 
                                aband->tmpqsos[i].ucallsign?COL_NORM:COL_INV);
                }else{
                    if (aband->tmpqsos[i].name){
                        int x;
                        x=18+1+strlen(c);
                        print_text(x, term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,32-x,
                                aband->tmpqsos[i].name, 
                                aband->tmpqsos[i].ucallsign?COL_NORM:COL_INV);
                    }
                }
            }
               
            c=aband->tmpqsos[i].rsts;
            if (c) print_text(36-strlen(c),term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,c,COL_NORM);
               
            if (ctest->qsoglob){
                if (i==0)
                    g_snprintf(s, sizeof(s), "%03d", ctest->allqsos->len+1);
                else
                    strcpy(s, "");
                c=s;
            }else{
                c=aband->tmpqsos[i].qsonrs;
            }
            if (c) print_text(40-strlen(c),term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,c,COL_NORM);
               
            c=aband->tmpqsos[i].rstr;
            if (c) print_text(45-strlen(c),term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,c,COL_NORM);
            
            c=aband->tmpqsos[i].qsonrr;
            if (c) print_text(49-strlen(c),term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,c,COL_NORM);
            
            c=aband->tmpqsos[i].exc;
            if (c) {
                safe_strncpy(exc, c, 11+1);
                print_text(50,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,exc,
                        aband->tmpqsos[i].uexc?COL_NORM:COL_INV);
            }

            c=aband->tmpqsos[i].locator;
            if (c) {
                char *susp_c;
                switch (aband->tmpqsos[i].susplocator){
                    case 1:
                        susp_c="?";
                        break;
                    case 2:
                        susp_c="!";
                        break;    
                    default:
                        susp_c=" ";
                        break;
                }
                print_text(55,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,c,
                    aband->tmpqsos[i].ulocator?COL_NORM:COL_INV);
                
                print_text(62,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,
                    susp_c, COL_RED);
            }
            
            a=(int)aband->tmpqsos[i].qrb;
			if (aband->tmpqsos[i].locator && *aband->tmpqsos[i].locator) {
                if (a<100000)
                    c=g_strdup_printf("%dkm",a);
                else
                    c=g_strdup_printf("%d",a);
                print_text(70-strlen(c),term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,c,
                    aband->tmpqsos[i].uqrb?COL_NORM:COL_INV);
                g_free(c);
            }

            a=aband->tmpqsos[i].qtf;
            if (a>=0) {
                c=g_strdup_printf("%d%c",a, degree);
                print_text(75-strlen(c),term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,c,
                    aband->tmpqsos[i].uqtf?COL_NORM:COL_INV);
                g_free(c);
               /* c=g_strdup_printf("(%d)",(a+180)%360);
                print_text(75,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,c,
                    aband->tmpqsos[i].uqtf?COL_NORM:COL_INV);
                g_free(c); */
            }
            if (i==0 && aband->tmpqsos[0].qsl){
                print_text(79,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,"q",COL_NORM);
            }
            c=aband->operator_;
            if (i==0 && c) print_text(81,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,c,COL_NORM);
            c=aband->tmpqsos[i].remark;
            if (c) print_text(89,term->y-cfg->loglines-spypeers-DISP_QSOS+i-1,-1,c,COL_NORM);
        }
        
        if (aband->unres) {
            int x;
            const int QRA_X=17;

            c=aband->unres;
            x=QRA_X-strlen(c);
            if (x<0) x=0;
            fill_area(0,term->y-2-cfg->loglines-spypeers, QRA_X,1,COL_BG);
            print_text(x,term->y-2-cfg->loglines-spypeers, QRA_X, c,COL_INV);
        }
        if (aband->wkd_str && aband->tmpqsos[1].callsign == NULL){
            const int QRA_X=17;
            c = aband->wkd_str;
            print_text(QRA_X+1,term->y-2-cfg->loglines-spypeers, QRA_X, c,COL_NORM);
        }
    }else{
        strcpy(s,mode_msg[get_mode()]);
        print_text(36-strlen(s),term->y-cfg->loglines-spypeers-DISP_QSOS-1,-1,s,COL_NORM);
#ifdef Z_ANDROID
        if (!aband){
            double h, w;
            int state;
            char ss[20], *st;
            //SDL_ANDROID_GetHW(&h, &w, &state);
            zandroid_get_location(&h, &w, &state);
            if (h > -1000 && h < 1000){
                switch (state){
                    case 0: st = "..."; break;
                    case 1: st = ""; break;
                    case 2: st = "?"; break;
                    default: st = "??"; break;
                }
                hw2loc(ss, h, w, 10);
                g_snprintf(s, 98, "%s%s", ss, st);
                print_text(3, 2,97,s,COL_NORM);
            } else{
                print_text(3, 2,97, VTEXT(T_LOCATION_UNKNOWN),COL_NORM);
            }
        }
#endif
    }
    il = INPUTLN(aband);
    c = aband ? "[ CLR ]" : "[ LOAD ]";
    print_text(il->x + il->l + 4, term->y - 1 - cfg->loglines - spypeers, -1, c, COL_INV);
        
/*        sw_default_redraw(g_ptr_array_index(ses->subwins,0));*/
    draw_time();
#if 0    
    else {
         c = VTEXT(T_SES_WELCOME);
         print_text((term->x-strlen(c))/2, term->y/2-3, -1, c, COL_NORM);
         c = VTEXT(T_SES_PRESS_F10);
         print_text((term->x-strlen(c))/2, term->y/2-1, -1, c, COL_NORM);
         c = VTEXT(T_SES_HAVE_FUN);
         print_text((term->x-strlen(c))/2, term->y/2+0, -1, c, COL_NORM);
         
         c = VTEXT(T_SES_URL);
         print_text((term->x-strlen(c))/2, term->y-5, -1, c, COL_NORM);
        
         print_tucnak(term->x-26,(term->y-12)/2-1);
#endif         
#if 0
         {
             int i,j;
             for (j=0;j<16;j++){
                for (i=0;i<16;i++){
                    unsigned char s[2];
                    
                    s[0]=i+j*16;
                    /*if (s[0]<32 || 
                        s[0]==127 ||
                        (s[0]>=128+0 && s[0]<128+32)) s[0]='.';*/
                    s[1]=0;
                    print_text(i+5,j+3, 1,s, COL((i&7)+j*8)); 
                }
                print_text(j,2, 1,"X", COL(j)); 
            }
         }
#endif         
#if 0
    }
#endif    
}


#define DELIM "\t\r\n "

#define FREE_Cx if (c1) {g_free(c1); c1=NULL;}\
                if (c2) {g_free(c2); c2=NULL;}\
                if (c3) {g_free(c3); c3=NULL;}\
                if (c4) {g_free(c4); c4=NULL;}\
                if (c5) {g_free(c5); c5=NULL;}


void add_tmpqso_rsts(struct band *band, gchar *rsts) {
    ADD_TMPQSO_STRING(band,rsts,rsts,1,udummy);
    add_date_time(band);
    band->last_item = LI_NONE;
    wkd_tmpqso(band, WT_RSTS, rsts);
}

void add_tmpqso_rstr(struct band *band, gchar *rstr) {
    ADD_TMPQSO_STRING(band,rstr,rstr,1,udummy);
    add_date_time(band);
    band->last_item = LI_NONE;
    wkd_tmpqso(band, WT_RSTR, rstr);
#ifdef HAVE_SNDFILE
	gssbd->code++;
#endif
}

int add_tmpqso_qsonrr(struct band *band, gchar *qsonrr){
    char s[20];
    int n;
    
    n=atoi(qsonrr);
    if (n<1 || n>9999) return -1;
    g_snprintf(s, 18, "%03d", n); 
    ADD_TMPQSO_STRING(band,qsonrr,s,1,udummy);
    wkd_tmpqso(band, WT_QSONRR, s);
#ifdef HAVE_SNDFILE
	gssbd->code++;
#endif
    return 0;
}

void add_tmpqso_exc(struct band *band,gchar *exc,int isu) {
    char s[20], *c;
    
    c = exc;
    if (ctest->exctype == EXC_WAZ || ctest->exctype == EXC_ITU){
        g_snprintf(s, 18, "%02d", atoi(exc)); 
        c = s;
    }
    ADD_TMPQSO_STRING(band, exc, c, isu, uexc);
    if (ctest->rstused!=1) add_date_time(band);
    band->last_item = LI_NONE;
    wkd_tmpqso(band, WT_EXC, c);
#ifdef HAVE_SNDFILE
	gssbd->code++;
#endif
}

void add_tmpqso_locator(struct band *band,gchar *wwl,int isu, int isshort) {
    int qtf_int;
    double qrb, qtf;
    char s[8];
    
    /* CHANGE look at recalc_all_qrbqtf */
    qrbqtf(ctest->pwwlo, wwl, &qrb, &qtf, NULL, 2);
    qtf_int=(int)(qtf+0.5);
    if (qrb < 0.1) {
        qrb=0;
        qtf_int=0;
    }  

    ADD_TMPQSO_GDOUBLE(band, qrb, qrb, isu, uqrb);
    ADD_TMPQSO_GINT(band, qtf, qtf_int, isu, uqtf);
    
    if (isshort)
        g_strlcpy(s, wwl, 4+1);
    else
		g_strlcpy(s, wwl, 6+1);
    
    ADD_TMPQSO_STRING(band,locator,s,isu,ulocator);
    if (ctest->rstused!=1) add_date_time(band);
#ifdef HAVE_SNDFILE
	gssbd->code++;
#endif
	ac_update_tmpctp(band->tmpqsos[0].locator);
}




void after_callsign(struct band *band,char *c, char *oldtmpqcall){
    gchar *wwl0, *wwl1, *wwl2, *name, *d, *exc0, *exc1, *exc2;
	struct qrv_item *qi;
    int done=0;
    char raw[20],raw1[20];
//  gchar *qrv_str;
    int unkcall=1;
//    struct qrv_item *qi;

    /*** name ***/
    zg_free0(band->tmpqsos[0].name);
    z_get_raw_call(raw,c);
    name = find_name_by_call(namedb, raw);
    if (name){
        band->tmpqsos[0].name = g_strdup(name);
        unkcall=0;
    }
     
    zg_free0(band->tmpqsos[1].name);
    z_get_raw_call(raw1, band->tmpqsos[1].callsign);
    name = find_name_by_call(namedb, raw1);
    if (name){
        band->tmpqsos[1].name = g_strdup(name);
    }
     
    /*** qrv string ***/
    compute_qrv_wkd(z_str_uc(c));
    
    /*** locator ***/

	if (!band->tmpqsos[0].ulocator && ctest->wwlused && ctest->phase > 1){
		struct qso *first = get_qso_by_callsign(aband, TMPQ.callsign);
		if (first != NULL) { add_tmpqso_locator(band, first->locator, 1, 0); done = 1; unkcall = 0; }
	}
	
	if (!done && !band->tmpqsos[0].ulocator && ctest->wwlused){

        wwl0 = find_wwl_by_call(cw, z_str_uc(c)); 
        wwl1 = find_wwl_by_call(cw, NULL); 
        wwl2 = find_wwl_by_oband(band, raw); /* yes, raw not c */
		qi = qrv_get(qrv, c);
        
        if (wwl1) {add_tmpqso_locator(band, wwl1, !ctest->wwlcfm, 0); done=1; unkcall=0;}
        if (wwl0) {add_tmpqso_locator(band, wwl0, !ctest->wwlcfm, 0); done=1; unkcall=0;}
        if (wwl2) {add_tmpqso_locator(band, wwl2, !ctest->wwlcfm, 0); done=1; unkcall=0;}
		if (qi)   {add_tmpqso_locator(band, qi->wwl, !ctest->wwlcfm, 0); done=1; unkcall=0;}
    }    

    /* try remove /p */
    if (!done && !band->tmpqsos[0].ulocator && ctest->wwlused){
        
        wwl0 = find_wwl_by_call(cw, z_str_uc(raw)); 
        wwl1 = find_wwl_by_call(cw, NULL); 
        wwl2 = find_wwl_by_oband(band, raw);
        
        if (wwl1) {add_tmpqso_locator(band, wwl1, !ctest->wwlcfm, 0); done=1; unkcall=0;}
        if (wwl0) {add_tmpqso_locator(band, wwl0, !ctest->wwlcfm, 0); done=1; unkcall=0;}
        if (wwl2) {add_tmpqso_locator(band, wwl2, !ctest->wwlcfm, 0); done=1; unkcall=0;}
		// no qrv_get, it strips /p itself
    }
        
    /* try add /p */
    if (!done && !band->tmpqsos[0].ulocator && ctest->wwlused){
        
        strcat(raw,"/P");
        wwl0 = find_wwl_by_call(cw, z_str_uc(raw)); 
        wwl1 = find_wwl_by_call(cw, NULL); 
        wwl2 = find_wwl_by_oband(band, raw);
		qi = qrv_get(qrv, c);
        
        if (wwl1) {add_tmpqso_locator(band, wwl1, !ctest->wwlcfm, 0); done=1; unkcall=0;}
        if (wwl0) {add_tmpqso_locator(band, wwl0, !ctest->wwlcfm, 0); done=1; unkcall=0;}
        if (wwl2) {add_tmpqso_locator(band, wwl2, !ctest->wwlcfm, 0); done=1; unkcall=0;}
		if (qi)   {add_tmpqso_locator(band, qi->wwl, !ctest->wwlcfm, 0); done=1; unkcall=0;}
    }
        
    if (!done && !band->tmpqsos[0].ulocator && ctest->wwlused){
            
        wwl0 = find_wwl_by_dxc_or_pref(dw, z_str_uc(c)); 
		wwl1 = find_wwl_by_dxc_or_pref(dw, NULL);
        
        if (wwl1) add_tmpqso_locator(band, wwl1, !ctest->wwlcfm, 1);
        if (wwl0) add_tmpqso_locator(band, wwl0, !ctest->wwlcfm, 1);
    }
    
    if (band->tmpqsos[0].ulocator && ctest->wwlused){
        int susp;
        if ((susp=get_susp_call(cw, dw, band->tmpqsos[0].callsign, band->tmpqsos[0].locator))!=0){
            band->tmpqsos[0].suspcallsign = susp;
        }else{
            band->tmpqsos[0].susplocator = 0;
            band->tmpqsos[0].suspcallsign = 0;
        }
    }else{ /* v kazdem pripade se bude kontrolovat susp_call */
        int susp;
        if ((susp=get_susp_call(cw, dw, band->tmpqsos[0].callsign, NULL))!=0){
            band->tmpqsos[0].suspcallsign = susp;
        }else{
            band->tmpqsos[0].susplocator = 0;
            band->tmpqsos[0].suspcallsign = 0;
        }

    }

    /******** EXC *********/
    
    if (!band->tmpqsos[0].uexc && ctest->excused > 0){

        exc0 = find_exc_by_call(excdb, z_str_uc(c)); 
        exc1 = find_exc_by_call(excdb, NULL); 
        exc2 = find_exc_by_oband(band, raw); /* yes, raw not c */
        
        if (exc1) {ADD_TMPQSO_STRING(band,exc,exc1,!ctest->exccfm,uexc); done=1; }
        if (exc0) {ADD_TMPQSO_STRING(band,exc,exc0,!ctest->exccfm,uexc); done=1; }
        if (exc2) {ADD_TMPQSO_STRING(band,exc,exc2,!ctest->exccfm,uexc); done=1; }
    }    

    
    band->tmpqsos[0].unkcall=unkcall;
#ifdef HAVE_SNDFILE
    ssbd_callsign(gssbd, c);
#endif
    wkd_tmpqso(band, WT_CALLSIGN, c);
    
    d=TMPQ.locator;
    map_clear_qso(&aband->tmplocqso, aband);
    zg_free0(aband->tmplocqso.locator);
    aband->tmplocqso.locator=g_strdup(d);
    if (d && *d){
        compute_qrbqtf(&aband->tmplocqso);
        map_add_qso(&aband->tmplocqso, aband);
    }
    //dbg("after_call(%d, %d==%d, oldtmpqcall=%s)\n", ctest->runmode, gses->mode, MOD_CW_CW, oldtmpqcall);
    if (ctest->runmode && gses->mode == MOD_CW_CW && oldtmpqcall == NULL){
        if (cfg->cwda_autgive > 0){  // we must omit call
            struct cq *cq = get_cq_by_number(cfg->cqs, 1);
            if (!cq){
                cq->stripcall = 1;
                //dbg("%s1: cq_run_by_number(1)\n", __FUNCTION__);
                cq_run_by_number(1); // 5NN $MX
                cq->stripcall = 0;
            }
        }else{
            //dbg("%s2: cq_run_by_number(1)\n", __FUNCTION__);
            cq_run_by_number(1); // $C 5NN $MX
            aband->iscall = 1;
            //dbg("after_call: set iscall=%d\n", aband->iscall);
        }
    }
	if (TMPQ.suspcallsign < 1){
		enum suspcall susp;
		struct qso *qso = g_new0(struct qso, 1);

        qso->callsign = TMPQ.callsign ? TMPQ.callsign : "";    /* foreign keys */
        qso->locator = TMPQ.locator ? TMPQ.locator : "";
        qso->rsts = TMPQ.rsts ? TMPQ.rsts : "";
        qso->qsonrs = TMPQ.qsonrs ? TMPQ.qsonrs : "";
        qso->rstr = TMPQ.rstr ? TMPQ.rstr : "";
        qso->qsonrr = TMPQ.qsonrr ? TMPQ.qsonrr : "";
		susp = qso_info(qso, NULL, NULL);
		if (susp == SUSP_WARN && TMPQ.suspcallsign < 1) TMPQ.suspcallsign = 1;
		if (susp == SUSP_ERR && TMPQ.suspcallsign < 2) TMPQ.suspcallsign = 2;
		g_free(qso);
	}

	update_susp(band);
}

void after_locator(struct band *band,char *c){
    gchar *call0, *call1;
    gchar *dxc0, *dxc1;
    int done=0;
    char raw[20], *name;

    dbg("after_locator('%s')\n", c);
    if (!band->tmpqsos[0].ucallsign){
        call0 = find_call_by_wwl(cw, z_str_uc(c));
        call1 = find_call_by_wwl(cw, NULL);


        if (call1) {
            ADD_TMPQSO_STRING(band,callsign,call1,0,ucallsign); 
            z_get_raw_call(raw,call1);
            name = find_name_by_call(namedb, raw);
            ADD_TMPQSO_STRING(band,name,name,0,udummy); 
            done=1;
        }
        if (call0) {
            ADD_TMPQSO_STRING(band,callsign,call0,0,ucallsign); 
            done=1;
            z_get_raw_call(raw,call0);
            name = find_name_by_call(namedb, raw);
            ADD_TMPQSO_STRING(band,name,name,0,udummy); 
        }
    }
    
    if (!done && !band->tmpqsos[0].ucallsign){
        dxc0 = find_dxc_by_wwl(dw, z_str_uc(c));
        dxc1 = find_dxc_by_wwl(dw, NULL);

        if (dxc1) ADD_TMPQSO_STRING(band,callsign,dxc1,0,ucallsign); 
        if (dxc0) ADD_TMPQSO_STRING(band,callsign,dxc0,0,ucallsign);
    }
    if (band->tmpqsos[0].ucallsign){
        int susp;
        if ((susp=get_susp(cw, dw, band->tmpqsos[0].callsign, band->tmpqsos[0].locator, 1))!=0){
            dbg("susp=%d\n", susp);
            band->tmpqsos[0].susplocator = susp & 0xff;
            band->tmpqsos[0].suspcallsign = susp >> 8;
        }else{
            band->tmpqsos[0].suspcallsign = 0;
            band->tmpqsos[0].susplocator = 0;
        }
    }
    wkd_tmpqso(band, WT_LOCATOR, c);
        
    map_clear_qso(&band->tmplocqso, band);

    zg_free0(band->tmplocqso.locator);
    band->tmplocqso.locator=g_strdup(c);
    if (c && *c){
        compute_qrbqtf(&band->tmplocqso);
        map_add_qso(&band->tmplocqso, band);
        redraw_later();
    }
    ac_update_tmpctp(c);
    
    if (ctest->runmode){
       // cq_run_by_number(2); // $B TU QRZ
        process_input(band, "", 0);
    }
	if (TMPQ.susplocator < 1){
		enum suspcall susp;
		struct qso *qso = g_new0(struct qso, 1);

		qso->callsign = TMPQ.callsign ? TMPQ.callsign : "";    /* foreign keys */
        qso->locator = TMPQ.locator ? TMPQ.locator : "";
        qso->rsts = TMPQ.rsts ? TMPQ.rsts : "";
        qso->qsonrs = TMPQ.qsonrs ? TMPQ.qsonrs : "";
        qso->rstr = TMPQ.rstr ? TMPQ.rstr : "";
        qso->qsonrr = TMPQ.qsonrr ? TMPQ.qsonrr : "";
		susp = qso_info(qso, NULL, NULL);
		if (susp == SUSP_WARN && TMPQ.susplocator < 1) TMPQ.susplocator = 1;
		if (susp == SUSP_ERR && TMPQ.susplocator < 2) TMPQ.susplocator = 2;
		g_free(qso);
	}
	update_susp(band);

}

void after_exc(struct band *band,char *c){
    if (ctest->runmode){
        //cq_run_by_number(2); // $B TU QRZ 
        process_input(band, "", 0);
    }
}

void after_qsonrr(struct band *band,char *c){
    if (ctest->runmode){
        //cq_run_by_number(2); // $B TU QRZ
        process_input(band, "", 0);
    }
}

void add_unres(struct band *band, gchar *c){
    gchar *tmpc;
    
    if (!band->unres){
        band->unres=g_strdup(c);
        return;
    }
    tmpc=g_strconcat(band->unres, " ", c, NULL);
    g_free(band->unres);
    band->unres=tmpc;
}

void add_date_time(struct band *band){
    char *d;
    time_t now;
    struct tm utc;

    time(&now);
    gmtime_r(&now, &utc);
   
    if (!band->tmpqsos[0].date_str){
        d=g_strdup_printf("%4d%02d%02d",1900+utc.tm_year, 1+utc.tm_mon, utc.tm_mday);
        ADD_TMPQSO_STRING(band,date_str,d,1,udummy);
        g_free(d);
    }
   
    if (!band->tmpqsos[0].time_str){
        d=g_strdup_printf("%02d%02d",utc.tm_hour, utc.tm_min);
        ADD_TMPQSO_STRING(band,time_str,d,1,udummy);
        g_free(d);
    }
}

void fix_date_time(struct band *band){
    struct qso *q;
    int i;
    gchar *last,*cur;

    if (!band->tmpqsos[0].date_str || 
        !band->tmpqsos[0].time_str){

        zg_free0(band->tmpqsos[0].date_str);
        zg_free0(band->tmpqsos[0].time_str);
        band->tmpqsos[0].date_str=NULL;
        band->tmpqsos[0].time_str=NULL;
        return;
    }
    /* tmpqso->date/time filled in */
    q=NULL;
    for (i=band->qsos->len-1;i>=0;i--){
        q=(struct qso *)g_ptr_array_index(band->qsos, i);
        if (q->error || q->dupe) {
            q=NULL;
            continue;
        }
        break;
    }
    if (!q) return;

    last=g_strconcat(q->date_str, q->time_str, NULL);
    cur=g_strconcat(band->tmpqsos[0].date_str, band->tmpqsos[0].time_str, NULL);
    if ((i=strcmp(last,cur))>0){
        zg_free0(band->tmpqsos[0].date_str);
        zg_free0(band->tmpqsos[0].time_str);
        band->tmpqsos[0].date_str=NULL;
        band->tmpqsos[0].time_str=NULL;
        return;
    }
/*    dbg("last=%s cur=%s ret=%d\n", last, cur, i);*/
    
    g_free(last);
    g_free(cur);
}

void process_input_no_contest(void *enterdata, gchar *text, int cq){
    char *s,*c;
    char *c1,*c2,*c3,*c4,*c5;
    char *token_ptr;
    
    c1=c2=c3=c4=c5=NULL;
    s=g_strdup(text);

    for (c=strtok_r(s,DELIM, &token_ptr); c!=NULL; c=strtok_r(NULL,DELIM, &token_ptr) ){
        /***** QRG ************************************************************/
        if (regmatch(c,"\\.([0-9][0-9][0-9])$",&c1,&c2,&c3,&c4,NULL)==0){
#ifdef HAVE_HAMLIB
            freq_t qrg;
            int khz;

            khz = atoi(c2);
            qrg = gtrigs->qrg;
            dbg("khz=%d qrg=%f\n", khz, qrg);
            qrg = floor(qrg/1000000.0) * 1000000.0 + khz * 1000.0;
            dbg("qrg=%f\n", qrg);
            trigs_set_qrg(gtrigs, qrg);
#endif
            continue;    
        }
        FREE_Cx;
        /***** FULL QRG in kHz  ************************************************************/
        if (regmatch(c,"\\.([0-9]{4,9})$",&c1,&c2,&c3,&c4,NULL)==0){
#ifdef HAVE_HAMLIB
            freq_t qrg;
            int khz;

            khz = atoi(c2);
            qrg = khz * 1000.0;
            dbg("khz=%d qrg=%f\n", khz, qrg);
            trigs_set_qrg(gtrigs, qrg);
#endif
            continue;    
        }
        FREE_Cx;
        if (strlen(c) > 0) call_info(NULL);
    }
    FREE_Cx;
    g_free(s);
}

void process_input(void *enterdata, char *text, int cq){
    char *s,*c;
/*    struct tmpqsos tq[TMP_QSOS];*/
    int num, ret;
    char *c1,*c2,*c3,*c4,*c5;
    char *token_ptr;
    struct band *band = (struct band *)enterdata;
    int qso_saved = 0;
    char *oldtmpqcall = NULL;
    
    //dbg("process_input('%s', cq=%d)\n", text, cq);
    c1=c2=c3=c4=c5=NULL;
    zg_free0(band->unres);
   /* zg_free0(band->qrv_str);*/
#ifdef HAVE_SNDFILE
    ssbd_watchdog(gssbd, 1);
#endif
    s=g_strdup(text);
    
    num=0;
    for (c=strtok_r(s,DELIM, &token_ptr); c!=NULL; c=strtok_r(NULL,DELIM, &token_ptr) ){
        num++;
/*        dbg("item='%s'\n",c);   */      /* /m /mm dl/ok1mzm/p */
        add_tmpxchg(band, c);
        FREE_Cx;


        if (ctest->exctype == EXC_VERIFIED){
            if (is_valid_vexc(excdb, c)){
                add_tmpqso_exc(band,c,1);
                after_exc(band,c);
                continue;    
            }
        }

        /***** Summit reference ****************************************/
        if (ctest->exctype == EXC_FREE){
            if (regcmp(c,"^[A-Z0-9]{1,4}/[A-Z]{2}-[0-9]{3}$")==0){
                add_tmpqso_exc(band, c, 1);
                continue;
            }
        }

        /***** LOCATOR *************************************************/
        if (regcmp(c,"^[A-R]{2}[0-9]{2}[A-X]{2}$")==0){
			if (TMPQ.callsign && !TMPQ.dupe){
				struct qso *dupe = stats_get_dupe(band->stats, TMPQ.callsign, TMPQ.locator, ctest->phase, gses->mode);
				if (dupe != NULL){
					band->dupe_qso = dupe;
					if (!band->ignoreswap){
						band->dupe_qso = dupe;
						compute_qrv_wkd(TMPQ.callsign);
						duplicate_callsign(dupe);
					}
					return;
				}
			}
            add_tmpqso_locator(band,c,1,0);
            band->last_item = LI_WWL;
            after_locator(band, c);
            continue;
        }
        FREE_Cx;

        if (ctest->wwlused == 3 || ctest->wwlused == 4){ // 3=used(4), 4=opt(4)
            if (regcmp(c,"^[A-R]{2}[0-9]{2}$")==0){
                add_tmpqso_locator(band,c,1,1);
                band->last_item = LI_WWL;
                after_locator(band, c);
                continue;
            }
            FREE_Cx;
        }
        
        /***** 2-3 digits 111-599 ***********************************************/
        if (regmatch(c,"^([1-5][1-9]{1,2})$", &c1, &c2, &c3, NULL)==0){
            switch (ctest->tttype){
                case TT_RSTS:
                    add_tmpqso_rsts(band, c2);
                    continue;
                case TT_RSTR:
                    add_tmpqso_rstr(band, c2);
                    continue;
                case TT_QSONRR:
                    add_tmpqso_qsonrr(band, c2);
                    after_qsonrr(band, c2);
                    continue;
                case TT_EXC:
                    add_tmpqso_exc(band, c2, 1);
                    after_exc(band,c2);
                    continue;
                default:
                    add_unres(band, c2);
                    continue;
            }
        }
        FREE_Cx;   
        /***** 2-3 digits 111-599 ***********************************************/
        if (regmatch(c,"^([1-5][1-9]{1,2}[ARMS]{0,1})$", &c1, &c2, &c3, NULL)==0){
            switch (ctest->tttype){
                case TT_RSTS:
                    add_tmpqso_rsts(band, c2);
                    continue;
                case TT_RSTR:
                    add_tmpqso_rstr(band, c2);
                    continue;
                case TT_EXC:
                    add_tmpqso_exc(band, c2, 1);
                    after_exc(band,c2);
                    continue;
                default:
                    add_unres(band, c2);
                    continue;
            }
        }
        FREE_Cx;   
        /***** three numbers ***********************************************/
		if (regmatch(c,"^([R1-5][1-9]{1,2})$", &c1, &c2, &c3, NULL)==0){
            switch (ctest->tttype){
                case TT_RSTS:
                    add_tmpqso_rsts(band, c2);
                    continue;
                case TT_RSTR:
                    add_tmpqso_rstr(band, c2);
                    continue;
                case TT_EXC:
                    add_tmpqso_exc(band, c2, 1);
                    after_exc(band,c2);
                    continue;
                default:
                    add_unres(band, c2);
                    continue;
            }
        }
        FREE_Cx;   
        /***** MS RST ***********************************************/
		if (regmatch(c,"^(R?[\\+\\-][0-9]{2})$", &c1, &c2, &c3, NULL)==0){
            switch (ctest->tttype){
                case TT_RSTS:
                    add_tmpqso_rsts(band, c2);
                    continue;
                case TT_RSTR:
                    add_tmpqso_rstr(band, c2);
                    continue;
                case TT_EXC:
                    add_tmpqso_exc(band, c2, 1);
                    after_exc(band,c2);
                    continue;
                default:
                    add_unres(band, c2);
                    continue;
            }
        }
        FREE_Cx;   /***** 2-3 digits 000-999 ***********************************************/
        if (regmatch(c,"^([0-9]{1,3})$", &c1, &c2, &c3, NULL)==0){
            switch (ctest->tttype){
                case TT_NONE:
                    continue;
                case TT_QSONRR:
                    add_tmpqso_qsonrr(band, c2);
                    after_qsonrr(band, c2);
                    continue;
                case TT_EXC:
                    add_tmpqso_exc(band, c2, 1);
                    after_exc(band,c2);
                    continue;
                default:
                    add_unres(band, c2);
                    continue;
            }
        }
        FREE_Cx;   
        /***** four digits QSO nr. ***********************************************/
        if (regmatch(c,"^([0-9]{4})$", &c1, &c2, NULL)==0){
            add_tmpqso_qsonrr(band, c2);
            after_qsonrr(band, c2);
            continue;
        }
        FREE_Cx;   
#if 0
        // matched by 2-3 digits or special RST
        /***** RST *************************************************/
        if (regcmp(c,"^[R1-5][1-9]{1,2}[ARMS]{0,2}$")==0){
            if (ctest->qsoused){
                add_tmpqso_rstr(band, c);
            }else{
                add_tmpqso_rsts(band, c); 
            }
            continue;
        }
        FREE_Cx;
#endif
        
        /***** RSTR ***********************************************/
        if (regmatch(c,"^([R1-5][1-9]{1,2}[ARMS]{0,2}),$", &c1, &c2, &c3, NULL)==0){
            add_tmpqso_rstr(band, c2);
            continue;
        }
        FREE_Cx;   

        /***** MS RSTR ***********************************************/
        if (regmatch(c,"^(R?[\\+\\-][0-9]{2}),$", &c1, &c2, &c3, NULL)==0){
            add_tmpqso_rstr(band, c2);
            continue;
        }
        FREE_Cx;   
        
        /***** RSTS ***********************************************/
        if (regmatch(c,"^([R1-5][X\\+\\-]?[1-9]{1,2}[ARMS]{0,2})['\\*]", &c1, &c2, &c3, NULL)==0){
            add_tmpqso_rsts(band, c2);
            continue;
        }
        FREE_Cx;   
        
        /***** MS RSTS ***********************************************/
        if (regmatch(c,"^(R?[\\+\\-][0-9]{2})['\\*]", &c1, &c2, &c3, NULL)==0){
            add_tmpqso_rsts(band, c2);
            continue;
        }
        FREE_Cx;   
        
        /***** QSONRR ***********************************************/
        if (regmatch(c,"^([0-9]{1,4});", &c1, &c2, &c3, NULL)==0){
            add_tmpqso_qsonrr(band, c2);
            after_qsonrr(band, c2);
            continue;
        }
        FREE_Cx;   
        
        if (ctest->excused>0 && !ctest->qsoused){
            /***** RST RECV + EXC ****************************************/
            if (get_mode() == MOD_CW_CW)
                ret=regmatch(c,"^([1-5][1-9]{2})[-_]?(.*)$",&c1,&c2,&c3,NULL);
            else
                ret=regmatch(c,"^([1-5][1-9]{1})[-_]?(.*)$",&c1,&c2,&c3,NULL);
            if (ret==0){
                char *d;
               
                d=c3;
                if (!is_valid_vexc(excdb, d)){
                    add_unres(band, d); 
                    continue;
                }
                add_tmpqso_exc(band,d,1);

                ADD_TMPQSO_STRING(band,rstr,c2,1,uexc);
                add_date_time(band);
                band->last_item = LI_NONE;
                wkd_tmpqso(band, WT_RSTR, c2);
#ifdef HAVE_SNDFILE
				gssbd->code++;
#endif
                
                after_exc(band,d);
                continue;
            }
            FREE_Cx;
        }
        
        /***** RST RECV + QSONR RECV ************************************/
        if (regmatch(c,"^([R1-5][1-9]{1,2}[ARMS]{0,2})[-_]?([0-9]{3,4})$",&c1,&c2,&c3,NULL)==0){
            if (add_tmpqso_qsonrr(band, c3) != 0){
                add_unres(band, c); 
                continue;
            }
            
            add_tmpqso_rstr(band, c2);
            after_qsonrr(band, c2);
            continue;
        }
        FREE_Cx;
        
        /***** MS RST RECV + QSONR RECV ************************************/
        if (regmatch(c,"^(R?[\\+\\-][0-9]{2})[-_]?([0-9]{3,4})$",&c1,&c2,&c3,NULL)==0){
            if (add_tmpqso_qsonrr(band, c3) != 0){
                add_unres(band, c); 
                continue;
            }
            
            add_tmpqso_rstr(band, c2);
            after_qsonrr(band, c2);
            continue;
        }
        FREE_Cx;
        
        /***** TIME ****************************************************/
        if (regmatch(c,"^([0-2]?[0-9])[:\\.]([0-5]?[0-9])$",&c1,&c2,&c3,NULL)==0){
            if (atoi(c2)>=24) { add_unres(band, c); continue;}
            c4=g_strdup_printf("%02d%02d",atoi(c2),atoi(c3)); 
            ADD_TMPQSO_STRING(band,time_str,c4,1,udummy);
            g_free(c4); c4=NULL;
            continue;
        }
        FREE_Cx;
        if (regmatch(c,"^[:\\.]([0-5]?[0-9])$",&c1,&c2,NULL)==0){
            time_t now;
            struct tm utc;

            time(&now);
            gmtime_r(&now, &utc);
            c4=g_strdup_printf("%02d%02d",utc.tm_hour, atoi(c2)); 
            ADD_TMPQSO_STRING(band,time_str,c4,1,udummy);
            g_free(c4); c4=NULL;
            continue;
        }
        FREE_Cx;
        
        /****** DATE **************************************************/
        if (regmatch(c,"^([0-9]{4})([0-9]{2})([0-9]{2})$",&c1,&c2,&c3,&c4, NULL)==0){
            int year,month,day;
                        
            /*dbg("%s %s %s %s\n",c1,c2,c3,c4);*/
/*            year  = atoi(c1);*/
            year  = atoi(c2);
            month = atoi(c3);
            day   = atoi(c4);
            if (year  < 1900 || year  > 3000 ||
                month < 1    || month > 12   ||
                day   < 1    || day   > 31) {
                    add_unres(band, c);
                    continue;             
            }

            ADD_TMPQSO_STRING(band,date_str,c,1,udummy);
            continue;
        }
        FREE_Cx;

#if 0        
           four digits is now QSO number

           if (regmatch(c,"^([0-9]{2})([0-9]{2})$",&c1,&c2,&c3, NULL)==0){
            int month,day;
            time_t now;
            struct tm utc;
            char s[40];
                        
            /*dbg("%s %s %s %s\n",c1,c2,c3,c4);*/
            month = atoi(c2);
            day   = atoi(c3);
            if (month < 1    || month > 12   ||
                day   < 1    || day   > 31) {
                    add_unres(band,c);
                    continue;   
            }

            time(&now);
            gmtime_r(&now, &utc);
            sprintf(s, "%04d%02d%02d", 1900+utc.tm_year, month, day);
            
            ADD_TMPQSO_STRING(band,date_str,s,1,udummy);
            continue;
        }
        FREE_Cx;
#endif        
        
        /****** /X, e.g. /P ***********************************************/
        if (regmatch(c,"^(\\/([A-Z0-9]{1,3})+)+$",&c1,&c2,&c3,&c4,NULL)==0){
            gchar *stroke, *newcall;
                  
			oldtmpqcall = band->tmpqsos[0].callsign;      
            /*dbg("%s %s %s %s\n",c1,c2,c3,c4);*/
            if (!band->tmpqsos[0].callsign) { add_unres(band,c); continue;}

            stroke = g_strdup(c1);
            FREE_Cx;

            if (regmatch(band->tmpqsos[0].callsign, 
                        "^([0-9A-Z]{1,3}\\/)?([0-9][A-Z]|[A-Z]{1,2}[0-9]{1,4}[A-Z]{1,3})(\\/([A-Z0-9]{1,3})+)+$", &c1, &c2, &c3, &c4, &c5, NULL)==0){
                if (c4 && strcmp(c4, stroke)==0)
                    newcall = g_strconcat(c2?c2:"", c3, NULL);
                else    
                    newcall = g_strconcat(c2?c2:"", c3, stroke, NULL);  
            }else{
                newcall = g_strconcat(band->tmpqsos[0].callsign, stroke, NULL);  
            }
            
            ADD_TMPQSO_STRING(band, callsign, newcall, 1, ucallsign); 
            after_callsign(band,newcall, oldtmpqcall);
            g_free(newcall);
            g_free(stroke);
#ifdef HAVE_SNDFILE
			gssbd->code++;
#endif
            continue;
        }
        FREE_Cx;
        
        /***** CALLSIGN 1 *************************************************/
        if (regcmp(c,"^([0-9A-Z]{1,3}\\/)?([0-9][A-Z]|[A-Z]{1,2}[0-9]?)[0-9]{1,4}[A-Z]{1,4}(\\/[A-Z0-9]{1,3})*$")==0){

            oldtmpqcall = band->tmpqsos[0].callsign;
			if (!TMPQ.dupe){
				struct qso *dupe = stats_get_dupe(band->stats, c, TMPQ.locator, ctest->phase, gses->mode);
				if (dupe != NULL){
					if (!band->ignoreswap){
						band->dupe_qso = dupe;
						compute_qrv_wkd(c);
						duplicate_callsign(dupe);
					}
					continue;
				}
			}

            ADD_TMPQSO_STRING(band,callsign,c,1,ucallsign);
            band->last_item = LI_CALL;
            after_callsign(band, c, oldtmpqcall);
#ifdef HAVE_SNDFILE
			gssbd->code++;
#endif
            continue;
        }
        FREE_Cx;
        
       /***** TWO LETTERS ****************************************************/
        if (regcmp(c,"^([A-Z][A-Z])$")==0){
            /*dbg("TWO %s \n", c);*/
#ifdef HAVE_SNDFILE
			gssbd->code++;
#endif
            if (band->last_item==LI_WWL){
                if (band->tmpqsos[0].locator &&
                    band->tmpqsos[0].ulocator){

                    band->tmpqsos[0].locator[4]='\0';
                    strcat(band->tmpqsos[0].locator, c);
                    after_locator(band,TMPQ.locator);
                }
                continue;
            }
            if (band->last_item==LI_CALL){
                goto nasty_hack;
            }
            add_unres(band, c); 
            continue;
        }
        FREE_Cx;
        
        
        /***** QSL CARD PROMISED *********************************************/
        if (strcasecmp(c,"q")==0){
            band->tmpqsos[0].qsl = !band->tmpqsos[0].qsl;
            continue;
        }

       /***** TWO DIGITS and TWO LETTERS ********************************************/
        if (regcmp(c,"^([0-9][0-9][A-Z][A-Z])$")==0){

/*          dbg("TWO and TWO %s \n", c);*/
            /*if (band->last_item==LI_WWL){
                if (band->tmpqsos[0].locator &&
                    band->tmpqsos[0].ulocator){

                    band->tmpqsos[0].locator[2]='\0';
                    strcat(band->tmpqsos[0].locator, c);
                    after_locator(band,TMPQ.locator);
                }
            }*/
			char s[20];
			strcpy(s, c);
			z_nearest_wwl(s, ctest ? ctest->pwwlo : cfg->pwwlo);
			add_tmpqso_locator(band, s, 1, 0);
            band->last_item = LI_WWL;
            after_locator(band, s);
#ifdef HAVE_SNDFILE
			gssbd->code++;
#endif
            continue;
        }
        FREE_Cx;
        
        
        /***** ONE OR THREE LETTERS *******************************************/
        if (regcmp(c,"^([A-Z]{1,3})$")==0){

            oldtmpqcall = band->tmpqsos[0].callsign;
            /*dbg("ONE OR THREE %s \n", c);*/
nasty_hack:;            
            FREE_Cx;
            if (band->tmpqsos[0].callsign && 
                band->tmpqsos[0].ucallsign &&
                regmatch(band->tmpqsos[0].callsign, 
                         "^([0-9A-Z]{1,3}\\/)?([0-9][A-Z]|[A-Z]{1,2}[0-9]{1,4})([A-Z]{1,3})((\\/[A-Z0-9]{1,3})*)$", 
                         &c1, &c2, &c3, &c4, &c5, NULL)==0){
                
                GString *gs;
                /*dbg("c1=%s\nc2=%s\nc3=%s\nc4=%s\nc5=%s\n", c1, c2, c3, c4, c5);*/

                gs=g_string_sized_new(20);

                if (c2) g_string_append(gs, c2);
                if (c3) g_string_append(gs, c3);
                if (c)  g_string_append(gs, c);
                if (c5) g_string_append(gs, c5);
                
				if (!TMPQ.dupe){
					struct qso *dupe = stats_get_dupe(band->stats, c, TMPQ.locator, ctest->phase, gses->mode);
					if (dupe != NULL){
						band->dupe_qso = dupe;
						if (!band->ignoreswap){
							band->dupe_qso = dupe;
							compute_qrv_wkd(c);
							duplicate_callsign(dupe);
						}
						g_string_free(gs, TRUE);
						continue;
					}
				}

                g_free(band->tmpqsos[0].callsign);
                band->tmpqsos[0].callsign=g_strdup(gs->str); /* ADD_TMPQSO_STRING */
                
                after_callsign(band, gs->str, oldtmpqcall);
                g_string_free(gs, TRUE);
#ifdef HAVE_SNDFILE
				gssbd->code++;
#endif
                
            }
            continue;
        }
        FREE_Cx;
        
        /***** REMARK ************************************************************/
        if (regmatch(c,"^#(.*)",&c1,&c2,&c3,&c4,NULL)==0){
            if (band->tmpqsos[0].remark) g_free(band->tmpqsos[0].remark);
            band->tmpqsos[0].remark=g_strdup(c2);
            fixsemi(band->tmpqsos[0].remark);
            continue;    
        }

        /***** EXC ************************************************************/
        if (regmatch(c,"(.*)\\.$",&c1,&c2,&c3,&c4,NULL)==0){
            if (!c2 || !*c2){
                add_tmpqso_exc(band, "nil", 1);
                wkd_tmpqso(band, WT_EXC, c2);
                continue;
            }
            if (!is_valid_vexc(excdb, c2)){
                add_unres(band, c2); 
                continue;
            }
            add_tmpqso_exc(band,c2,1);
            after_exc(band,c2);
            continue;    
        }
        FREE_Cx;

        /***** QRG ************************************************************/
        if (regmatch(c,"\\.([0-9][0-9][0-9])$",&c1,&c2,&c3,&c4,NULL)==0){
#ifdef HAVE_HAMLIB
            freq_t qrg;
			int khz;

            khz = atoi(c2);
            qrg = gtrigs->qrg;
            dbg("khz=%d qrg=%f\n", khz, qrg);
            qrg = floor(qrg/1000000.0) * 1000000.0 + khz * 1000.0;
            dbg("qrg=%f\n", qrg);
            trigs_set_qrg(gtrigs, qrg);
#endif
            continue;    
        }
        FREE_Cx;
        /***** FULL QRG in kHz  ************************************************************/
		if (regmatch(c,"\\.([0-9]{4,9})$",&c1,&c2,&c3,&c4,NULL)==0){
#ifdef HAVE_HAMLIB
            freq_t qrg;
			int khz;

            khz = atoi(c2);
            qrg = khz * 1000.0;
            dbg("khz=%d qrg=%f\n", khz, qrg);
            trigs_set_qrg(gtrigs, qrg);
#endif
            continue;    
        }
        FREE_Cx;

        /***** CALLSIGN 2 *************************************************/
        if (regmatch(c,"^([0-9A-Z]+)/$",&c1,&c2,&c3,&c4,NULL)==0){
            
            oldtmpqcall = band->tmpqsos[0].callsign;
			if (!TMPQ.dupe){
				struct qso *dupe = stats_get_dupe(band->stats, c, TMPQ.locator, ctest->phase, gses->mode);
				if (dupe != NULL){
					if (!band->ignoreswap){
						band->dupe_qso = dupe;
						compute_qrv_wkd(c);
						duplicate_callsign(dupe);
					}
					continue;
				}
			}

            ADD_TMPQSO_STRING(band,callsign,c2,1,ucallsign);
            band->last_item = LI_CALL;
            after_callsign(band, c2, oldtmpqcall);
            continue;
        }
        FREE_Cx;
        /***** EXC ***********************************************************/
        if (ctest->exctype == EXC_FREE || ctest->exctype == EXC_MULTIPLIED){  // better than unresolved, f.e. DOKs cannot colide
            if (is_valid_vexc(excdb, c)){
                add_tmpqso_exc(band,c,1);
                after_exc(band,c);
                continue;    
            }
        }
        
        
    /* item is unresolved */
        add_unres(band, c);
        FREE_Cx;
    }
    FREE_Cx;

    if (!num){
        if (band->tmpqsos[0].callsign && band->tmpqsos[0].ucallsign &&
			((band->tmpqsos[0].rsts && *band->tmpqsos[0].rsts) || ctest->rstused != 1) &&  /* 0=no/1=yes */
            (band->tmpqsos[0].rstr    || ctest->rstused!=1) &&
            (band->tmpqsos[0].qsonrr  || ctest->qsoused!=1) &&
             ((band->tmpqsos[0].exc     && band->tmpqsos[0].uexc) || ctest->excused!=1) &&
             ((band->tmpqsos[0].locator && band->tmpqsos[0].ulocator) || ctest->wwlused!=1) &&
             can_cq(aband)
           )
            {    
            struct qso *q;
            
            fix_date_time(band);
            
            add_date_time(band);
            
            q=g_new0(struct qso,1);
            

            q->source    = g_strdup(gnet->myid);
            q->stamp     = time(NULL);
            q->date_str  = g_strdup(band->tmpqsos[0].date_str);
            q->time_str  = g_strdup(band->tmpqsos[0].time_str);
            q->callsign  = g_strdup(band->tmpqsos[0].callsign);
            q->operator_ = g_strdup(band->operator_);
            q->rsts      = g_strdup(band->tmpqsos[0].rsts?band->tmpqsos[0].rsts:"");
            q->rstr      = g_strdup(band->tmpqsos[0].rstr?band->tmpqsos[0].rstr:"");
            if (ctest->qsoglob){
                q->qsonrs = g_strdup_printf("%03d", ctest->allqsos->len+1);
            }else{
                q->qsonrs = g_strdup(band->tmpqsos[0].qsonrs?band->tmpqsos[0].qsonrs:"");
            }
            q->qsonrr   = g_strdup(band->tmpqsos[0].qsonrr?band->tmpqsos[0].qsonrr:"");
            if (band->tmpqsos[0].ulocator){
                q->locator  = g_strdup(band->tmpqsos[0].locator);
                q->qrb      = band->tmpqsos[0].qrb;
                q->qtf      = band->tmpqsos[0].qtf;
            }else{
                q->locator  = g_strdup("");
            }
            
            q->dupe     = band->tmpqsos[0].dupe;
            q->qsop     = 0; /* update_stats */
            q->qsl      = band->tmpqsos[0].qsl;
            q->remark   = g_strdup(band->tmpqsos[0].remark?band->tmpqsos[0].remark:"");
            fixsemi(q->remark);
			q->phase    = ctest->phase;
            if (band->tmpqsos[0].exc){
                    if (strcmp(band->tmpqsos[0].exc, "nil")!=0)
                    q->exc = g_strdup(band->tmpqsos[0].exc);
                else
                    q->exc = g_strdup("");
            }else{
                q->exc = g_strdup("");
            }
/*            q->serial   = ctest->serial++;*/
#ifdef HAVE_HAMLIB
			if (gtrigs->trigs->len > 0 && 
                gtrigs->qrg >= band->qrg_min * 1000.0 &&
                gtrigs->qrg <= band->qrg_max * 1000.0) 
                
                q->qrg = gtrigs->qrg;
            else
#endif                
                q->qrg = 0.0;
            
            if (get_mode() == MOD_SSB_SSB ||
                get_mode() == MOD_CW_CW){
                
                int s,r;
                /* CHANGE menu2.c refresh_edit_qso */
                s=strlen(q->rsts);
                r=strlen(q->rstr);
                if (s==3 && r==3) q->mode=MOD_CW_CW;
                if (s==2 && r==2) q->mode=MOD_SSB_SSB;
                if (s==3 && r==2) q->mode=MOD_CW_SSB;
                if (s==2 && r==3) q->mode=MOD_SSB_CW;
            }else{
				q->mode = get_mode();
			}
            
            q->ser_id=-1; /* computed by add_qso_to_index */
            compute_qrbqtf(q);  /* for kx & ky */
            add_qso(band,q);
            write_qso_to_swap(band, q);
            replicate_qso(NULL, q);
            update_stats(band, band->stats, q);
            recalc_allb_stats();
            minute_stats(band);

            recalc_statsfifo(band);
            recalc_worked_skeds(band);
#ifdef HAVE_SNDFILE            
            if (ssbd_recording(gssbd)){
                ssbd_abort(gssbd,1);
                ssbd_abort(gssbd,0);
            }
#endif
            check_autosave();
            map_add_qso(q, aband);
            map_clear_qso(&band->tmplocqso, aband);
            ctrl_back(band);
            chart_reload(); // only aband
#ifdef HAVE_HAMLIB
            if (ctest->runmode){
				int i;
				for (i = 0; i < gtrigs->trigs->len; i++){
					struct trig *trig = (struct trig *)g_ptr_array_index(gtrigs->trigs, i);
					if (trig->clr_rit) {
						trig_set_rit(trig, 0.0);
					}
				}
            }
			ac_track(gacs, NULL, -1);
#endif
            qso_saved = 1;
        }
    }
    dbg("process_input(runmode=%d, len=%d, cq=%d, last_cq=%p)\n", ctest->runmode, strlen(text), cq, gses->last_cq);
    if (qso_saved){
        if (gses->mode == MOD_CW_CW && ctest->runmode && strlen(text)==0){  // tady muzeme prepsat $C 5NN $MX, pokud se znacka opravuje a zadava se vsechno najednou
            cq_run_by_number(2); // $B TU QRZ
        }
        clear_tmpqsos(band,1);  
    }else{
        if (gses->mode == MOD_CW_CW && ctest->runmode && strlen(text)==0 && cq!= 0 && gses->last_cq == NULL){
            if (band->tmpqsos[0].callsign){
                cq_run_by_number(1); // $C 5NN $MX
            }else{
                cq_run_by_number(0); // CQ $MC TEST
            }
        }
    }    
    
    g_free(s);
    redraw_later();

}

void draw_time(void){
    char s[100];
    time_t now;
    struct tm utc;
    int color;

    time(&now);
    gmtime_r(&now, &utc);
           
    sprintf(s, " %d:%02d:%02d ", utc.tm_hour, utc.tm_min, utc.tm_sec);
#ifdef Z_UNIX
    color=COL_RED;
    if (ntpq && ntpq->good) 
#endif
    color=COL_NORM;

    print_text(term->x-6-strlen(s),0,11,s,color);

}


void time_func(void *arg){
    struct timeval tv;
    int remains;

    /*gettimeofday(&tv, NULL);
    dbg("usec=%06d\n", tv.tv_usec);*/
    /* disable time drawing when bfu is active */
    //if (term->windows.next == term->windows.prev ||
//		gses->win->prev->handler == cwwindow_func)
	if (gses->win->prev->handler != mainmenu_func)
        draw_time();

    gettimeofday(&tv, NULL);
    remains=1000-(tv.tv_usec/1000);
    /*dbg("usec=%06d remains=%d\n", tv.tv_usec, remains);*/
    
    gses->timer_id = zselect_timer_new(zsel, remains, time_func, NULL);
}


void print_tucnak(int x, int y){
    int col_black, col_white, col_yellow;
    
    
    if (term->spec->col){
        col_black=COL(0x38);/* 3f */
        col_white=COL(0x7f);
        col_yellow=COL(0x7b);
    }else{
        col_black=COL(0x70);
        col_white=COL(0x3f);
        col_yellow=COL(0x7b);
    }

    fill_area( x-1, y-1, 23, 14, col_black);
    print_text(x+8, y,   -1,"#####",col_black);
    print_text(x+7, y+1, -1,"#######",col_black);
    print_text(x+7, y+2, -1,"#######",col_black);
    print_text(x+9, y+2,  1,"O",col_white);
    print_text(x+11,y+2,  1,"O",col_white);
    print_text(x+7, y+3, -1,"#######",col_black);
    print_text(x+8, y+3, -1,"#####",col_yellow);
    
    print_text(x+5, y+4, -1,"##",col_black);
    print_text(x+7, y+4, -1,"##",col_white);
    print_text(x+9 ,y+4, -1,"###",col_yellow);
    print_text(x+12,y+4, -1,"##",col_white);
    print_text(x+14,y+4, -1,"##",col_black);
    
    print_text(x+4, y+5, -1,"#",col_black);
    print_text(x+5, y+5, -1,"##########",col_white);
    print_text(x+15,y+5, -1,"##",col_black);
    
    print_text(x+3, y+6, -1,"#",col_black);
    print_text(x+4, y+6, -1,"############",col_white);
    print_text(x+16,y+6, -1,"##",col_black);
    
    print_text(x+3, y+7, -1,"#",col_black);
    print_text(x+4, y+7, -1,"############",col_white);
    print_text(x+16,y+7, -1,"###",col_black);
    
    print_text(x+2 ,y+8, -1,"##",col_yellow);
    print_text(x+4, y+8, -1,"#",col_black);
    print_text(x+5, y+8, -1,"###########",col_white);
    print_text(x+16,y+8, -1,"##",col_black);
    print_text(x+18,y+8,-1,"#",col_yellow);
    
    print_text(x   ,y+9, -1,"######",col_yellow);
    print_text(x+6, y+9, -1,"#",col_black);
    print_text(x+7, y+9, -1,"########",col_white);
    print_text(x+14,y+9, -1,"#",col_black);
    print_text(x+15,y+9,-1,"######",col_yellow);
    
    print_text(x   ,y+10,-1,"#######",col_yellow);
    print_text(x+7, y+10,-1,"#",col_black);
    print_text(x+8, y+10,-1,"######",col_white);
    print_text(x+13,y+10,-1,"#",col_black);
    print_text(x+14,y+10,-1,"#######",col_yellow);
    
    print_text(x+2, y+11,-1,"#####",col_yellow);
    print_text(x+7, y+11,-1,"########",col_black);
    print_text(x+14,y+11,-1,"#####",col_yellow);
    
}

void clear_hicalls(){
	g_hash_table_foreach_remove(gses->hicalls, zg_hash_free_item, NULL);
}

int load_hicalls_from_file(char *filename){
    FILE *f;
    gchar *c;
    GString *gs;

	clear_hicalls();
    
    f=fopen(filename, "rt");
    if (!f) return 1;


    gs = g_string_sized_new(100);
    while( (c=zfile_fgets(gs, f, 0)) != NULL){
		struct zstring *zstr = zstrdup(gs->str);
		char *call = ztokenize(zstr, 1);
		char *sval = ztokenize(zstr, 0);
		int *val = g_new(int, 1);
		if (sval) 
			*val = atoi(sval);
		else
			*val = 1;
        g_hash_table_insert(gses->hicalls, g_strdup(call), val);
		zfree(zstr);
    }
    g_string_free(gs, 1);
    fclose(f);
    return 0;
}

void save_one_hicall(gpointer key, gpointer value, gpointer user_data){
    GString *gs;
    gchar *call;
	int val;


    gs   = (GString *) user_data;
    call = (gchar *) key;
	val = *((int*)value);
	zg_string_eprintfa("e", gs, "%s;%d\r\n", call, val);
}

int save_hicalls_to_file(char *filename){
    FILE *f;
    int ret;
    GString *gs;

    f = fopen(filename, "wb");
    if (!f){
        log_addf(VTEXT(T_CANT_WRITE_S), filename);
        return errno;
    }
    
    gs=g_string_sized_new(1000);
    g_hash_table_foreach(gses->hicalls, save_one_hicall, (gpointer) gs);
    
    ret = fprintf(f,"%s",gs->str) != gs->len ? errno: 0;
    g_string_free(gs, 1);
    fclose(f);
    return ret;
}

void update_hw(){
	gchar *pwwlo;

	if (!gses) return;

    if (ctest && ctest->pwwlo) {
        pwwlo=ctest->pwwlo;
    }else{
        pwwlo = cfg->pwwlo;
    }
    if (!pwwlo) zinternal("Undefined locator");
    
	gses->myh = qth(pwwlo, 0);
	gses->myw = qth(pwwlo, 1);
}

void update_susp(struct band *b){
	if (!b) return;

	int i, is_susp = 0;
	for (i = 0; i < DISP_QSOS; i++){
		if (b->tmpqsos[i].ucallsign && b->tmpqsos[i].ulocator && (b->tmpqsos[i].suspcallsign || b->tmpqsos[i].susplocator)) is_susp = 1;
		if (b->tmpqsos[i].ucallsign && b->tmpqsos[i].uexc && (b->tmpqsos[i].suspcallsign || b->tmpqsos[i].suspexc)) is_susp = 1;
	}
	INPUTLN(b)->is_susp = is_susp;
	redraw_later();
}

