コード例 #1
0
ファイル: commands.c プロジェクト: iamroger/voip
/* Reads install prefix from user */
int read_install_prefix(select_menu *menu,void *arg)
{
	#define query_msg		"Enter install prefix "
	#define folder_ok		"Folder exists and is accesible "
	char str[256];
	int ret,len;

	print_notice(NOTICE_Y,NOTICE_X,0,"%s (Current = '%s') :",query_msg,
			install_prefix?install_prefix:DEFAULT_INSTALL_PREFIX);
	
	/* print directory that user is typing */
	echo();

	ret=getstr(str);
	if (ret != 0) {
		fprintf(output,"Failed to read new install prefix\n");
		return -1;
	}

	/* disable echoing character on the window */
	noecho();

	/* Empty directory = default directory */
	if (strlen(str) != 0) {
		prev_prefix=install_prefix;

		len = strlen(str);
		install_prefix = malloc(str[len-1]=='/'?len+1:len+2);
		if (!install_prefix) {
			fprintf(output,"No more mem\n");
			return -1;
		}
	
		memset(install_prefix,0,str[len-1]=='/'?len+1:len+2);
		memcpy(install_prefix,str,len);
		if (str[len-1] != '/')
			install_prefix[len]='/';

		print_notice(NOTICE_Y,NOTICE_X,0,"%s. Install prefix is currently [%s]",folder_ok,
			install_prefix?install_prefix:DEFAULT_INSTALL_PREFIX);
		clrtoeol();
		print_notice(NOTICE_Y+1,NOTICE_X,1,"Press any key to continue !");
		clrtoeol();
	} else {
		/* NULL = default prefix */
		prev_prefix=install_prefix;
		install_prefix=NULL;
		print_notice(NOTICE_Y,NOTICE_X,0,"%s. Install prefix is currently [%s]",folder_ok,
			install_prefix?install_prefix:DEFAULT_INSTALL_PREFIX);
		clrtoeol();	
		print_notice(NOTICE_Y+1,NOTICE_X,1,"Press any key to continue !");
		clrtoeol();
	}

	menu->child_changed=CHILD_CHANGED;
	return 0;
}
コード例 #2
0
ファイル: commands.c プロジェクト: iamroger/voip
/* Resets all unsaved compile related options */
int reset_unsaved_compile(select_menu *menu,void *arg)
{
	select_menu *current;
	select_item *it;

	current=find_menu(CONF_EXCLUDED_MODS,main_menu);
	for (it=current->item_list;it;it=it->next)
		it->enabled=it->prev_state;
	current->child_changed=CHILD_NO_CHANGES;

	current=find_menu(CONF_COMPILE_FLAGS,main_menu);
	for (it=current->item_list;it;it=it->next)
		it->enabled=it->prev_state;
	current->child_changed=CHILD_NO_CHANGES;

	current=find_menu(CONF_INSTALL_PREFIX,main_menu);
	if (install_prefix != prev_prefix) {
		if (install_prefix) {
			free(install_prefix);
			install_prefix=NULL;
		}
		install_prefix=prev_prefix;
	}
	current->child_changed=CHILD_NO_CHANGES;

	
	print_notice(NOTICE_Y,NOTICE_X,1,"Changes have been reset. Press any key to continue");

	return 0;
}
コード例 #3
0
ファイル: query_menu.c プロジェクト: treblih/chafing_dish
void *query_menu(int x, int format_x, char *sql, FUNCP callback, void *cb_arg, int col, ...)
{
	va_list field;
	va_start(field, col);
	int col_type[col];
	for (int i = 0; i < col; ++i) {
		col_type[i] = va_arg(field, int);
	}
	char **res = db_select(get_db_main(), sql, col, col_type);

	if (callback) {
		struct daily_total *total = (struct daily_total *)callback(res, cb_arg);
		print_notice("今日截止目前共%d笔生意  总收入%.1f  总成本%.1f  总盈利%.1f\n" 
			     "平均每桌盈利%.1f",
			     total->cnt,
			     total->sales,
			     total->cost,
			     total->profil,
			     total->profil / total->cnt);
	}

	mt.x = x;
	mt.format_x = format_x;
	mt.choice = res;
	mt.choice_n = get_sql_item_cnt();
	mt.win = get_win(W_MID);
	mt.format_y = LINES - 3;

	menu_interact(&mt);
	free(res);
	return NULL;
}
コード例 #4
0
ファイル: commands.c プロジェクト: iamroger/voip
/* Saves all the configured changes
 * for the cfg entry associated to the current menu
 */
int save_m4_def(select_menu *menu,void *arg)
{
	char *p;
	select_menu *items_menu = menu->prev_sibling;
	select_item *it;
	cfg_gen_t *m4_cfg;
	static char cfg_path[256];
	FILE *f;

	/* A little bogus, maybe menu should have back-pointer to cfg entry */
	p = memchr(items_menu->name,' ',strlen(items_menu->name));
	if (!p) {
		fprintf(output,"Invalid menu name [%s]\n",items_menu->name);
		return -1;
	}
	
	p++;
	m4_cfg = find_cfg_entry(p);
	
	if (!m4_cfg) {
		fprintf(output,"Failed to find cfg entry for %s\n",items_menu->name);
		return -1;
	}

	memcpy(cfg_path,run_locally?"menuconfig/configs/":MENUCONFIG_CFG_PATH,
			run_locally?19:MENUCONFIG_CFG_PATH_LEN);
	memcpy(cfg_path+(run_locally?19:MENUCONFIG_CFG_PATH_LEN),
			m4_cfg->defs_m4,strlen(m4_cfg->defs_m4)+1);
	
	f = fopen(cfg_path,"w");
	if (!f) {
		fprintf(output,"Failed to open m4 defs\n");
		return -1;
	}

	fprintf(f,"divert(-1)\n");
	for (it=items_menu->item_list;it;it=it->next) {
		fprintf(f,"define(`%s', `%s') #%s\n",it->name,it->enabled?"yes":"no",
			it->description);
	}
	fprintf(f,"divert");

	if (arg == NULL) {
		print_notice(NOTICE_Y,NOTICE_X,1,"Script configurations saved for %s. Press any key to continue !",m4_cfg->name);
	}

	fclose(f);
	items_menu->child_changed=CHILD_NO_CHANGES;
	return 0;
}
コード例 #5
0
ファイル: draw.c プロジェクト: senlinms/C-RPG
void draw_system(World * w)
{
	char hp_str[32];
	sprintf(hp_str, "HP:%7d", w->hero->hp);
	set_str((CHAR_INFO *) screen_buffer, hp_str, 62, 0, 0, 4 + 8);
	print_gauge(62, 1, w->hero->max_hp, w->hero->hp, 4 + 8, 4);
	char mp_str[32];
	sprintf(mp_str, "MP:%7d", w->hero->mp);
	set_str((CHAR_INFO *) screen_buffer, mp_str, 62, 2, 0, 1 + 8);
	print_gauge(62, 3, w->hero->max_mp, w->hero->mp, 1 + 8, 1);
	print_mode(62, 4, w->hero);
	print_notice(w->hero, 0, 21);
	draw_examine(60, 20, w, w->hero->x, w->hero->y, w->hero);
}
コード例 #6
0
ファイル: commands.c プロジェクト: iamroger/voip
/* Save all related compile options to Makefile.conf*/
int dump_make_conf(select_menu *menu,void *arg)
{
	select_menu *current;
	select_item *it;
	int i,k=0;

	FILE *f = fopen(MAKE_CONF_FILE,"w");

	/* START compile MODULES related options */
	current = find_menu(CONF_EXCLUDED_MODS,main_menu);
	for (it=current->item_list;it;it=it->next) {
		for (i=0;i<it->dependency_no;i++) {
			if (i==0)
				fprintf(f,"#%s=%s|%s\n",it->name,it->description,it->dependency[i]);
			else
				fprintf(f,"#%s=%s\n",it->name,it->dependency[i]);
			if (it->enabled) {
				print_notice(NOTICE_Y+k++,NOTICE_X,0,
					"You have enabled the '%s' module, so please install '%s'\n",
					it->name,it->dependency[i]);
			}
		}
		it->prev_state=it->enabled;
	}

	print_notice(NOTICE_Y+k,NOTICE_X,1,"Press any key to continue\n");

	fprintf(f,"\nexclude_modules?= ");
	for (it=current->item_list;it;it=it->next) {
		fprintf(f,"%s ",it->name);
	}

	fprintf(f,"\n\ninclude_modules?= ");
	for (it=current->item_list;it;it=it->next) {
		if (it->enabled)
			fprintf(f,"%s ",it->name);
	}

	current->child_changed=CHILD_NO_CHANGES;
	/* END compile MODULES related options */
	fprintf(f,"\n\n");

	/* START compile DEFS related options */
	current = find_menu(CONF_COMPILE_FLAGS,main_menu);
	for (it=current->item_list;it;it=it->next) {
		fprintf(f,"%sDEFS+= -D%s #%s",
			it->enabled?"":"#",it->name,it->description);
		if (strcmp(it->name,"USE_TLS") == 0 && it->enabled)
			fprintf(f,"TLS=1\n");
		else if (strcmp(it->name,"USE_SCTP") == 0 && it->enabled)
			fprintf(f,"SCTP=1\n");
		it->prev_state=it->enabled;
	}

	current->child_changed=CHILD_NO_CHANGES;
	/* END compile DEFS related options */
	
	/* START install prefix related options */
	current=find_menu(CONF_INSTALL_PREFIX,main_menu);
	fprintf(f,"\nPREFIX=%s",install_prefix?install_prefix:DEFAULT_INSTALL_PREFIX);
	
	prev_prefix=install_prefix;
	current->child_changed=CHILD_NO_CHANGES;
	/* END install prefix related options */

	fclose(f);
	return 0;
}
コード例 #7
0
ファイル: commands.c プロジェクト: iamroger/voip
/* Generates an actual cfg based on users selected
 * m4 defs
*/
int generate_cfg(select_menu *menu,void *arg)
{
	static char generated_name[128];
	static char defs_cfg_path[256];
	static char cfg_path[256];
	char *p;
	cfg_gen_t *m4_cfg;
	int n,ret,fd,status;
	time_t now;
	struct tm *now_tm;
	select_menu *items_menu = menu->prev_sibling->prev_sibling;

	/* Kind of bogus. Maybe menu should have backpointer to cfg entry */
	p = memchr(items_menu->name,' ',strlen(items_menu->name));
	if (!p) {
		fprintf(output,"Invalid menu name [%s]\n",items_menu->name);
		return -1;
	}
	
	p++;
	m4_cfg = find_cfg_entry(p);

	if (!m4_cfg) {
		fprintf(output,"Failed to find cfg entry for %s\n",items_menu->name);
		return -1;
	}

	/* Save everything that was configured */
	if (save_m4_def(menu->prev_sibling,(void *)1) < 0) {
		fprintf(output,"Failed to save m4 defs\n");
		return -1;
	}

	/* generate config name */
	now=time(NULL);
	now_tm = localtime(&now);
	n = snprintf(generated_name,128,"%sopensips_%s_%d-%d-%d_%d:%d:%d.cfg",
			run_locally?"etc/":MENUCONFIG_GEN_PATH,
			m4_cfg->output_name,now_tm->tm_year+1900,now_tm->tm_mon+1,
			now_tm->tm_mday,now_tm->tm_hour,now_tm->tm_min,now_tm->tm_sec);
	if (n<0 || n>128) {
		fprintf(output,"Failed to create command to generate cfg\n");
		return -1;
	}

	/* skip all the signal crap. M4 should be much much faster than make install */
	ret = fork();
	if (ret < 0) {
		fprintf(output,"Failed to fork process \n");
		return -1;
	} else if (ret > 0) {
		/* parent */
		wait(&status);
		print_notice(NOTICE_Y,NOTICE_X,1,
			"Config generated : %s =  %s. Press any key to continue",
			generated_name,status?"FAILED":"SUCCESS");
	} else {
		fd = open(generated_name,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR);
		if (fd < 0) {
			fprintf(output,"Failed to open output file\n");
			exit(-1);
		}

		memcpy(cfg_path,run_locally?"menuconfig/configs/":MENUCONFIG_CFG_PATH,
				run_locally?19:MENUCONFIG_CFG_PATH_LEN);
		memcpy(cfg_path+(run_locally?19:MENUCONFIG_CFG_PATH_LEN),
				m4_cfg->cfg_m4,strlen(m4_cfg->cfg_m4)+1);
		memcpy(defs_cfg_path,run_locally?"menuconfig/configs/":MENUCONFIG_CFG_PATH,
				run_locally?19:MENUCONFIG_CFG_PATH_LEN);
		memcpy(defs_cfg_path+(run_locally?19:MENUCONFIG_CFG_PATH_LEN),
				m4_cfg->defs_m4,strlen(m4_cfg->defs_m4)+1);
		/* child */
		/* redirect child output to generated file name */
		dup2(fd,STDOUT_FILENO);
		close(fd);
		execlp("m4","m4",defs_cfg_path,cfg_path,(char *)0);
		fprintf(output,"Failed to execute\n");
		exit(-1);
	}

	return 0;
}
コード例 #8
0
ファイル: commands.c プロジェクト: AndreiPlesa/opensips
/* Save all related compile options to Makefile.conf*/
int dump_make_conf(select_menu *menu,void *arg)
{
	select_menu *current;
	select_item *it;
	int i,k=0;
	int start_grp=0, prev_grp=0;

	FILE *f = fopen(MAKE_CONF_FILE,"w");
	if (!f) {
		fprintf(stderr,"Failed to open [%s]\n",MAKE_CONF_FILE);
		return -1;
	}

	/* START compile MODULES related options */
	current = find_menu(CONF_EXCLUDED_MODS,main_menu);
	for (it=current->item_list;it;it=it->next) {
		for (i=0;i<it->dependency_no;i++) {
			if (i==0)
				fprintf(f,"#%s=%s|%s\n",it->name,it->description,it->dependency[i]);
			else
				fprintf(f,"#%s=%s\n",it->name,it->dependency[i]);
			if (it->enabled) {
				print_notice(NOTICE_Y+k++,NOTICE_X,0,
					"You have enabled the '%s' module, so please install '%s'\n",
					it->name,it->dependency[i]);
			}
		}
		it->prev_state=it->enabled;
	}

	print_notice(NOTICE_Y+k,NOTICE_X,1,"Press any key to continue\n");

	fprintf(f,"\nexclude_modules?= ");
	for (it=current->item_list;it;it=it->next) {
		fprintf(f,"%s ",it->name);
	}

	fprintf(f,"\n\ninclude_modules?= ");
	for (it=current->item_list;it;it=it->next) {
		if (it->enabled)
			fprintf(f,"%s ",it->name);
	}

	current->child_changed=CHILD_NO_CHANGES;
	/* END compile MODULES related options */
	fprintf(f,"\n\n");

	/* START compile DEFS related options */
	current = find_menu(CONF_COMPILE_FLAGS,main_menu);
	for (it=current->item_list;it;it=it->next) {
		if (it->group_idx && !start_grp) {
			start_grp = 1;
			prev_grp = it->group_idx>0 ? it->group_idx : -it->group_idx;
			fprintf(f, "%s\n", GRP_START_STR);
		}
		if (start_grp)
			if ((it->group_idx>0 && (it->group_idx != prev_grp)) ||
				(it->group_idx<0 && (-it->group_idx != prev_grp)) ||
				it->group_idx==0) {
				start_grp = 0;
				fprintf(f, "%s\n", GRP_END_STR);
			}

		fprintf(f,"%sDEFS+= -D%s #%s",
			it->enabled?"":"#",it->name,it->description);
		it->prev_state=it->enabled;
	}

	if (!it && start_grp)
		fprintf(f, "%s\n", GRP_END_STR);

	current->child_changed=CHILD_NO_CHANGES;
	/* END compile DEFS related options */

	/* START install prefix related options */
	current=find_menu(CONF_INSTALL_PREFIX,main_menu);
	fprintf(f,"\nPREFIX=%s",install_prefix?install_prefix:DEFAULT_INSTALL_PREFIX);

	prev_prefix=install_prefix;
	current->child_changed=CHILD_NO_CHANGES;
	/* END install prefix related options */

	fclose(f);
	return 0;
}
コード例 #9
0
ファイル: ripv2_server.c プロジェクト: jsdario/rysca
int main(int argc, char * argv[]) {

    system("clear");

    signal(SIGINT, interrupt);

    ipv4_addr_t multiaddress;

    ipv4_str_addr (RIP_MULTICAST_IPv4, multiaddress);

    if(argc == 2) {
        if( !strcmp(argv[1], "--verbose")) {
            is_verbose = 1;
            print_warning("(Debug mode ON) \n");
        }
    }
    else
        printf("(Run with --verbose to print more info)\n");

    bold ("Starting RIP Server... \t\t\t\t\t");
    print_success("[ OK ]\n");

    table = rip_table_create ();
    if (initialize_rip (table, RIP_PORT) == -1) {
        /* Already printed advert inside function */
        return -1;
    }
    int K = rip_route_table_read ( RIP_TABLE_TXT, table );

    /* set inf timer to routes read from file */
    int k;
    for( k = 0; k < K; k++ ) {

        timerms_reset(&table->routes[k]->time, INFINITE_TIMER);
    }

    rip_table_t * table_aux;

    ipv4_addr_t src;
    long int r = random_number(-15, 15)*1000;
//SEND UNSOLICITED RESPONSE MESSAGES EVERY 30 SECONDS +- 15s
    timerms_t update_timer = timer_start ( UPDATE_TIME + r );

//SEND REQUEST TO FILL ROUTE TABLE

    rip_route_table_print ( table );

    for ( ;; ) {

        if (timer_ended (update_timer)) {

            /* Si se ha acabado el update timer */
            send_rip_response (multiaddress, message_ptr, table, RIP_PORT);
            r = random_number(-15, 15)*1000;
            if ( is_verbose ) printf("(update_time set to %ld)\n", r +UPDATE_TIME);
            update_timer = timer_start (UPDATE_TIME + r);

            bold ("\nCurrent table:\n");
            rip_route_table_print ( table );

        }
        int src_port;

        int bytes_received = rip_recv (src, message_ptr, MIN_TIMER, &src_port);

//WE RECEIVE A MESSAGE
        if (bytes_received>0) {

            //WE CONVERT THE MESSAGE TO A ROUTE TABLE FORMAT
            table_aux = convert_message_table (message_ptr, rip_number_entries(bytes_received));

            if ( is_verbose ) {

                print_notice ("\nReceived packet\n");
                print_packet (message_ptr, rip_number_entries(bytes_received));
            }

//IF THE MESSAGE IS A RESPONSE...
            if (message_ptr->command == 2) {

                //VALIDATE (HAY QUE IMPLEMENTARLO)
                //number of entries in the received message
                int num_entries = rip_number_entries (bytes_received);

                int trig_update_flag = 0; //by default, when receiving, do not send update

                //AND THIS IS WHERE THE MAGIC HAPPENS, WE PROCESS THE RESPONSE MESSAGE
                trig_update_flag = compare_tables (table, table_aux, num_entries, src);


                if (trig_update_flag) {

                    send_rip_response (multiaddress, message_ptr, table, RIP_PORT);

                }
                bold ("\nCurrent table:\n");
                rip_route_table_print ( table );
            }

            if (message_ptr->command == 1 &&
                    metric_is_inf(ntohl(message_ptr->entry[0].metric))) {
                //IF REQUEST FOR WHOLE TABLE, RESPOND WITH WHOLE TABLE

                print_warning("Received a request for single entry, sending whole table\n");

                send_rip_response (src, message_ptr, table, src_port);

            }  else if (message_ptr->command == 1) {
//IF REQUEST FOR SPECIFIC ENTRIES, RESPOND WITH SPECIFIC ENTRIES IF FOUND

                print_warning("Received a request for specific entries\n");
                rip_table_t * table_send = table_to_send (table, table_aux);
                send_rip_response (src, message_ptr, table_send, src_port);

            }
        }


        int is_garbage_on = garbage_collector_start (table, garbage_collector_timers);
        int garbage_collected = garbage_collector (table, garbage_collector_timers);

        if (garbage_collected || is_garbage_on) {

            if(garbage_collected)  print_notice("Garbage Collected \n");
            else if(is_garbage_on) print_notice("Garbage countdown ON\n");
            if( is_verbose ) rip_route_table_print(table);
        }
    }

    return 0;
}
コード例 #10
0
ファイル: curses.c プロジェクト: WuKongQC/opensips
int draw_sibling_menu(select_menu *menu)
{
	int i,c,maxopt,d;
	char buf[40];
	select_menu *it;
	int cur_index=0;
	int skip=0;
	int max_len=0,len;
again:
	wclear(menu_window);

	/* print title in colour */
	attron(COLOR_PAIR(1));
	mvprintw(HIGH_NOTICE_Y,max_x/2-20,menu->parent?menu->parent->name:"OpenSIPS Main Configuration Menu");
	/* print footer */
	print_notice(NOTICE_Y,NOTICE_X,0,"Press h for navigation help.");
	attroff(COLOR_PAIR(1));

	/* draw actual menu */
	i=0;
	for (it=menu;it;it=it->next_sibling) {
		wmove(menu_window, max_y/4+i++, max_x / 2 - 20);
		snprintf(buf, sizeof(buf), " %s", it->name);
		waddstr(menu_window, buf);
		len = strlen(it->name) +6;
		if (len > max_len)
			max_len = len;
	}

	/* draw selection marker */
	wmove(menu_window, max_y/4+cur_index, (max_x / 2) - 25);
	waddstr(menu_window, "--->");

	/* print box with color */
	wattron(menu_window,COLOR_PAIR(2));
	for (d=-1;d<i+1;d++) {
		wmove(menu_window,max_y/4+d,max_x/2-30);
		wprintw(menu_window,"|");
		wmove(menu_window,max_y/4+d,max_x/2-20+max_len);
		wprintw(menu_window,"|");
	}

	for (d=0;d<max_len+9;d++) {
		wmove(menu_window,max_y/4-2,max_x/2-29+d);
		wprintw(menu_window,"_");
		wmove(menu_window,max_y/4+i,max_x/2-29+d);
		wprintw(menu_window,"_");
	}

	wattroff(menu_window,COLOR_PAIR(2));
	wmove(menu_window, 0, 0);
	wrefresh(menu_window);

	maxopt = i-1;

	c = getch();
	switch (c) {
		case KEY_UP:
			if (cur_index > 0)
				cur_index--;
			break;
		case KEY_DOWN:
			if (cur_index < maxopt)
				cur_index++;
			break;
		case KEY_RIGHT:
		case KEY_ENTER:
		case '\n':
			for (i=0,it=menu;i<cur_index;i++,it=it->next_sibling)
				;
			c = exec_menu_action(it);
			break;
		case 'h':
		case 'H':
			clear();
			print_notice(max_y/2,20,0,"Use UP and DOWN arrow keys to navigate.");
			print_notice(max_y/2+1,20,0,"Use RIGHT arrow or ENTER key to enter a certain menu.");
			print_notice(max_y/2+2,20,0,"Use LEFT arror or Q key to go back.");
			print_notice(max_y/2+3,20,0,"Use SPACE to toggle an entry ON/OFF.\n");
			print_notice(max_y/2+4,20,1,"Press any key to return to menuconfig.");
			refresh();
			break;
		case KEY_LEFT:
		case 'q':
		case 'Q':
			for (it=menu;it;it=it->next_sibling) {
				if (it->child_changed == CHILD_CHANGED) {
					if (skip == 0) {
						/* have we asked before and got negative response ? */
						print_notice(NOTICE_Y,NOTICE_X,0,"You have not saved changes. Go back anyway ? [y/n] ");
						c = getch();
						if (c == 'n' || c == 'N')
							goto again;
						else {
							it->child_changed = CHILD_CHANGE_IGNORED;
							skip=1;
							return 0;
						}
					} else
						it->child_changed = CHILD_CHANGE_IGNORED;
				}
			}
			if (skip == 1)
				return 0;
			return 0;
	}

	goto again;
}
コード例 #11
0
ファイル: curses.c プロジェクト: WuKongQC/opensips
int draw_item_list(select_menu *menu)
{
	select_item *it;
	int i=0,j=0,k=0,d,sc=0;
	int c,curopt=0;
	char buf[40];
	select_item *current=NULL;
	int should_scroll,max_display;
	int len,max_len=0;
	int disp_start=0,actual_pos=0;
again:
	i=0;j=0;k=0;
	max_display=max_y/2-2;
	should_scroll=menu->item_no>max_display?1:0;

	wclear(menu_window);

	/* print title in colour */
	attron(COLOR_PAIR(1));
	mvprintw(HIGH_NOTICE_Y,max_x/2-20,menu->name);
	attroff(COLOR_PAIR(1));

	if (should_scroll) {
		for (it=menu->item_list,sc=0;it;it=it->next,sc++) {
			/* only draw visible part of menu */
			if (sc>=disp_start && i < max_display) {
				wmove(menu_window, max_y/4+j++, max_x / 2 - 20);
				i++;
				snprintf(buf, sizeof(buf), "[%s] %s", it->enabled ? "*" : " ", it->name);
				waddstr(menu_window, buf);
				len=strlen(it->name);
				if (len > max_len)
					max_len=len;
			}
		}
	} else {
		for (it=menu->item_list,sc=0;it;it=it->next,sc++) {
			/* draw everything */
			wmove(menu_window, max_y/4+j++, max_x / 2 - 20);
			i++;
			snprintf(buf, sizeof(buf), "[%s] %s", it->enabled ? "*" : " ", it->name);
			waddstr(menu_window, buf);
			len=strlen(it->name);
			if (len > max_len)
				max_len=len;
		}

		/* marker is always in par with the selected option */
		actual_pos=curopt;
	}

	for(it=menu->item_list;it;it=it->next)
		if (k++ == curopt) {
			current=it;
			break;
		}

	/* print current item description */
	if (current->description) {
		attron(COLOR_PAIR(1));
		print_notice(NOTICE_Y,NOTICE_X,0,current->description);
		attroff(COLOR_PAIR(1));
	}

	move(max_y/4+actual_pos,max_x/2-19);

	/* draw box */
	wattron(menu_window,COLOR_PAIR(2));
	for (d=-1;d<i+1;d++) {
		wmove(menu_window,max_y/4+d,max_x/2-26);
		wprintw(menu_window,"|");
		wmove(menu_window,max_y/4+d,max_x/2-10+max_len);
		wprintw(menu_window,"|");
	}

	for (d=0;d<max_len+15;d++) {
		wmove(menu_window,max_y/4-2,max_x/2-25+d);
		wprintw(menu_window,"_");
		wmove(menu_window,max_y/4+i,max_x/2-25+d);
		wprintw(menu_window,"_");
	}

	/* show scrolling notifications if it's the case */
	if (should_scroll && disp_start > 0) {
		wmove(menu_window,max_y/4,max_x/2-5+max_len);
		wprintw(menu_window,"Scroll up for more");
	}

	if (should_scroll && disp_start + max_display < menu->item_no) {
		wmove(menu_window,max_y/4+max_display-1,max_x/2-5+max_len);
		wprintw(menu_window,"Scroll down for more");
	}

	wattroff(menu_window,COLOR_PAIR(2));

	wrefresh(menu_window);
	k=0;

	while ((c = getch())) {
		switch (c) {
			case KEY_UP:
				if (should_scroll && curopt != 0) {
					if (curopt == disp_start) {
						disp_start--;
						actual_pos=0;
					} else
						actual_pos--;
					curopt--;
				} else if (curopt!=0) {
					curopt--;
				}
				break;
			case KEY_DOWN:
				if (should_scroll && curopt < menu->item_no-1) {
					if (curopt == (disp_start+max_display-1)) {
						disp_start++;
						actual_pos=i-1;
					} else
						actual_pos++;
					curopt++;
				} else if (curopt < i-1) {
					curopt++;
				}
				break;
			case ' ':
				for (it=menu->item_list;it;it=it->next) {
					if (k++ == curopt) {
						it->enabled=it->enabled?0:1;
						menu->child_changed=CHILD_CHANGED;
					}
				}
				break;
			case KEY_LEFT:
			case 'q':
			case 'Q':
				wclear(menu_window);
				return 0;
		}

		goto again;
	}

	return 0;
}