Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

bbslist.c 32.1 KB
Newer Older
1 2 3 4
#include <stdio.h>
#include <stdlib.h>

#include <dirwrap.h>
5
#include <ini_file.h>
6
#include <uifc.h>
7
#include "filepick.h"
8
#include "allfonts.h"
9

10
#include "syncterm.h"
deuce's avatar
deuce committed
11
#include "fonts.h"
12 13
#include "bbslist.h"
#include "uifcinit.h"
14
#include "conn.h"
15
#include "ciolib.h"
16 17
#include "keys.h"
#include "mouse.h"
18
#include "cterm.h"
19 20
#include "window.h"
#include "term.h"
21

22 23
char *screen_modes[]={"Current", "80x25", "80x28", "80x43", "80x50", "80x60", NULL};
char *log_levels[]={"Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Info", "Debug", NULL};
24
char *log_level_desc[]={"None", "Alerts", "Critical Errors", "Errors", "Warnings", "Notices", "Normal", "All (Debug)", NULL};
25

26
char *rate_names[]={"300bps", "600bps", "1200bps", "2400bps", "4800bps", "9600bps", "19.2Kbps", "38.4Kbps", "57.6Kbps", "76.8Kbps", "115.2Kbps", "Unlimited", NULL};
27
int rates[]={300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 0};
28

deuce's avatar
deuce committed
29
char *music_names[]={"ESC [ | only", "BANSI Style", "All ANSI Music enabled", NULL};
30

31 32 33 34 35 36 37
ini_style_t ini_style = {
	/* key_len */ 15, 
	/* key_prefix */ "\t", 
	/* section_separator */ "\n", 
	/* value_separarator */NULL, 
	/* bit_separator */ NULL };

38 39 40 41 42 43 44 45 46 47 48 49 50
void viewofflinescroll(void)
{
	int	top;
	int key;
	int i;
	char	*scrnbuf;
	struct	text_info txtinfo;
	int	x,y;
	struct mouse_event mevent;

	x=wherex();
	y=wherey();
    gettextinfo(&txtinfo);
51
	scrnbuf=(char *)alloca(txtinfo.screenheight*txtinfo.screenwidth*2);
52 53 54 55 56 57 58 59 60
	gettext(1,1,txtinfo.screenwidth,txtinfo.screenheight,scrnbuf);
	uifcbail();
	drawwin();
	top=scrollback_lines;
	gotoxy(1,1);
	textattr(uifc.hclr|(uifc.bclr<<4)|BLINK);
	for(i=0;!i;) {
		if(top<1)
			top=1;
61
		if(top>(int)scrollback_lines)
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
			top=scrollback_lines;
		puttext(((txtinfo.screenwidth-80)/2)+1,1,(txtinfo.screenwidth-80)/2+80,txtinfo.screenheight,scrollback_buf+(80*2*top));
		cputs("Scrollback");
		gotoxy(71,1);
		cputs("Scrollback");
		gotoxy(1,1);
		key=getch();
		switch(key) {
			case 0xff:
			case 0:
				switch(key|getch()<<8) {
					case CIO_KEY_MOUSE:
						getmouse(&mevent);
						switch(mevent.event) {
							case CIOLIB_BUTTON_1_DRAG_START:
								mousedrag(scrollback_buf);
								break;
						}
						break;
					case CIO_KEY_UP:
						top--;
						break;
					case CIO_KEY_DOWN:
						top++;
						break;
					case CIO_KEY_PPAGE:
						top-=txtinfo.screenheight;
						break;
					case CIO_KEY_NPAGE:
						top+=txtinfo.screenheight;
						break;
					case CIO_KEY_F(1):
						init_uifc(FALSE, FALSE);
						uifc.helpbuf=	"`Scrollback Buffer`\n\n"
										"~ J ~ or ~ Up Arrow ~   Scrolls up one line\n"
										"~ K ~ or ~ Down Arrow ~ Scrolls down one line\n"
										"~ H ~ or ~ Page Up ~    Scrolls up one screen\n"
										"~ L ~ or ~ Page Down ~  Scrolls down one screen\n";
						uifc.showhelp();
						uifcbail();
						drawwin();
						break;
				}
				break;
			case 'j':
			case 'J':
				top--;
				break;
			case 'k':
			case 'K':
				top++;
				break;
			case 'h':
			case 'H':
				top-=txtinfo.screenheight;
				break;
			case 'l':
			case 'L':
				top+=txtinfo.screenheight;
				break;
			case ESC:
				i=1;
				break;
		}
	}
	init_uifc(TRUE, TRUE);
	puttext(1,1,txtinfo.screenwidth,txtinfo.screenheight,scrnbuf);
	gotoxy(x,y);
	return;
}

133 134
int get_rate_num(int rate)
{
deuce's avatar
deuce committed
135
	int i;
136

137 138
	for(i=0; rates[i] && (!rate || rate > rates[i]); i++);
	return(i);
139 140 141
}

int get_next_rate(int curr_rate) {
deuce's avatar
deuce committed
142
	int i;
143 144 145 146

	if(curr_rate == 0)
		i=0;
	else
147
		i=get_rate_num(curr_rate)+1;
148 149
	return(rates[i]);
}
150

151 152 153 154 155 156
void sort_list(struct bbslist **list)  {
	struct bbslist *tmp;
	unsigned int	i,swapped=1;

	while(swapped) {
		swapped=0;
157
		for(i=1;list[i]!=NULL && list[i-1]->name[0] && list[i]->name[0];i++) {
158 159 160 161 162 163 164 165 166 167 168
			int	cmp=stricmp(list[i-1]->name,list[i]->name);
			if(cmp>0) {
				tmp=list[i];
				list[i]=list[i-1];
				list[i-1]=tmp;
				swapped=1;
			}
		}
	}
}

169 170 171 172 173 174 175 176 177
void free_list(struct bbslist **list, int listcount)
{
	int i;

	for(i=0;i<listcount;i++) {
		free(list[i]);
	}
}

178
void read_item(FILE *listfile, struct bbslist *entry, char *bbsname, int id, int type)
179 180
{
	BOOL	dumb;
181
	char	home[MAX_PATH+1];
182

183
	get_syncterm_filename(home, sizeof(home), SYNCTERM_DEFAULT_TRANSFER_PATH, FALSE);
184 185 186
	if(bbsname != NULL)
		strcpy(entry->name,bbsname);
	iniReadString(listfile,bbsname,"Address","",entry->addr);
187 188
	entry->conn_type=iniReadEnum(listfile,bbsname,"ConnectionType",conn_types,CONN_TYPE_RLOGIN);
	entry->port=iniReadShortInt(listfile,bbsname,"Port",conn_ports[entry->conn_type]);
189 190 191 192 193 194 195 196 197 198 199 200 201 202
	entry->added=iniReadDateTime(listfile,bbsname,"Added",0);
	entry->connected=iniReadDateTime(listfile,bbsname,"LastConnected",0);
	entry->calls=iniReadInteger(listfile,bbsname,"TotalCalls",0);
	iniReadString(listfile,bbsname,"UserName","",entry->user);
	iniReadString(listfile,bbsname,"Password","",entry->password);
	iniReadString(listfile,bbsname,"SystemPassword","",entry->syspass);
	dumb=iniReadBool(listfile,bbsname,"BeDumb",0);
	if(dumb)
		entry->conn_type=CONN_TYPE_RAW;
	entry->reversed=iniReadBool(listfile,bbsname,"Reversed",0);
	entry->screen_mode=iniReadEnum(listfile,bbsname,"ScreenMode",screen_modes,SCREEN_MODE_CURRENT);
	entry->nostatus=iniReadBool(listfile,bbsname,"NoStatus",0);
	iniReadString(listfile,bbsname,"DownloadPath",home,entry->dldir);
	iniReadString(listfile,bbsname,"UploadPath",home,entry->uldir);
203 204

	/* Log Stuff */
rswindell's avatar
rswindell committed
205
	iniReadString(listfile,bbsname,"LogFile","",entry->logfile);
206 207 208
	entry->xfer_loglevel=iniReadEnum(listfile,bbsname,"TransferLogLevel",log_levels,LOG_INFO);
	entry->telnet_loglevel=iniReadEnum(listfile,bbsname,"TelnetLogLevel",log_levels,LOG_INFO);

209 210
	entry->bpsrate=iniReadInteger(listfile,bbsname,"BPSRate",0);
	entry->music=iniReadInteger(listfile,bbsname,"ANSIMusic",CTERM_MUSIC_BANSI);
211
	iniReadString(listfile,bbsname,"Font","Codepage 437 English",entry->font);
212
	entry->type=type;
213
	entry->id=id;
214 215
}

216 217 218 219
/*
 * Reads in a BBS list from listpath using *i as the counter into bbslist
 * first BBS read goes into list[i]
 */
220
void read_list(char *listpath, struct bbslist **list, struct bbslist *defaults, int *i, int type)
221 222
{
	FILE	*listfile;
223 224 225
	char	*bbsname;
	str_list_t	bbses;

226
	if((listfile=fopen(listpath,"r"))!=NULL) {
227
		if(defaults != NULL)
228
			read_item(listfile,defaults,NULL,-1,type);
229
		bbses=iniReadSectionList(listfile,NULL);
230
		while((bbsname=strListPop(&bbses))!=NULL) {
231 232
			if((list[*i]=(struct bbslist *)malloc(sizeof(struct bbslist)))==NULL)
				break;
233
			read_item(listfile,list[*i],bbsname,*i,type);
234
			(*i)++;
235 236
		}
		fclose(listfile);
237
		strListFreeStrings(bbses);
238 239
	}

240
#if 0	/* This isn't necessary (NULL is a sufficient) */
241 242
	/* Add terminator */
	list[*i]=(struct bbslist *)"";
243
#endif
244 245
}

246
int edit_list(struct bbslist *item,char *listpath,int isdefault)
247
{
248 249
	char	opt[18][80];	/* <- Beware of magic number! */
	char	*opts[19];		/* <- Beware of magic number! */
250 251 252
	int		changed=0;
	int		copt=0,i,j;
	char	str[6];
253 254 255
	FILE *listfile;
	str_list_t	inifile;
	char	tmp[LIST_NAME_MAX+1];
256
	char	*itemname;
257

258
	for(i=0;i<18;i++)		/* <- Beware of magic number! */
deuce's avatar
deuce committed
259
		opts[i]=opt[i];
260
	if(item->type==SYSTEM_BBSLIST) {
deuce's avatar
deuce committed
261 262
		uifc.helpbuf=	"`Cannot edit system BBS list`\n\n"
						"SyncTERM supports system-wide and per-user lists.  You may only edit entries"
263
						"in your own personal list.\n";
264 265 266
		uifc.msg("Cannot edit system BBS list");
		return(0);
	}
267 268 269 270
	if((listfile=fopen(listpath,"r"))!=NULL) {
		inifile=iniReadFile(listfile);
		fclose(listfile);
	}
271
	else {
272
		inifile=strListInit();
273 274 275 276
	}

	if(isdefault)
		itemname=NULL;
277
	else
278
		itemname=item->name;
279
	for(;;) {
280 281 282 283 284 285 286 287 288 289 290 291 292 293
		i=0;
		if(!isdefault) {
			sprintf(opt[i++], "BBS Name          %s",itemname);
			sprintf(opt[i++], "Address           %s",item->addr);
		}
		sprintf(opt[i++], "Port              %hu",item->port);
		sprintf(opt[i++], "Username          %s",item->user);
		sprintf(opt[i++], "Password          ********");
		sprintf(opt[i++], "System Password   %s",item->syspass[0]?"********":"<none>");
		sprintf(opt[i++], "Connection        %s",conn_types[item->conn_type]);
		sprintf(opt[i++], "Reversed          %s",item->reversed?"Yes":"No");
		sprintf(opt[i++], "Screen Mode       %s",screen_modes[item->screen_mode]);
		sprintf(opt[i++], "Hide Status Line  %s",item->nostatus?"Yes":"No");
		sprintf(opt[i++], "Download Path     %s",item->dldir);
294 295
		sprintf(opt[i++], "Upload Path       %s",item->uldir);
		sprintf(opt[i++], "Log File          %s",item->logfile);
rswindell's avatar
rswindell committed
296
		sprintf(opt[i++], "Log Transfers     %s",log_level_desc[item->xfer_loglevel]);
297
		sprintf(opt[i++], "Log Telnet Cmds   %s",log_level_desc[item->telnet_loglevel]);
298 299 300
		sprintf(opt[i++], "Simulated BPS     %s",rate_names[get_rate_num(item->bpsrate)]);
		sprintf(opt[i++], "ANSI Music        %s",music_names[item->music]);
		sprintf(opt[i++], "Font              %s",item->font);
301
		opts[i]=NULL;
302
		uifc.changes=0;
deuce's avatar
deuce committed
303 304 305

		uifc.helpbuf=	"`Edit BBS`\n\n"
						"Select item to edit.";
306 307 308 309
		i=uifc.list(WIN_MID|WIN_SAV|WIN_ACT,0,0,0,&copt,NULL,"Edit Entry",opts);
		if(i>=0 && isdefault)
			i+=2;
		switch(i) {
310
			case -1:
311 312 313 314 315
				if(!safe_mode) {
					if((listfile=fopen(listpath,"w"))!=NULL) {
						iniWriteFile(listfile,inifile);
						fclose(listfile);
					}
316 317
				}
				strListFreeStrings(inifile);
318 319
				return(changed);
			case 0:
deuce's avatar
deuce committed
320 321
				uifc.helpbuf=	"`BBS Name`\n\n"
								"Enter the BBS name as it is to appear in the list.";
322 323 324
				strcpy(tmp,itemname);
				uifc.input(WIN_MID|WIN_SAV,0,0,"BBS Name",itemname,LIST_NAME_MAX,K_EDIT);
				iniRenameSection(&inifile,tmp,itemname);
325 326
				break;
			case 1:
327
				uifc.helpbuf=	"`Address`\n\n"
deuce's avatar
deuce committed
328 329
								"Enter the domain name of the system to connect to ie:\n"
								"nix.synchro.net";
330
				uifc.input(WIN_MID|WIN_SAV,0,0,"Address",item->addr,LIST_ADDR_MAX,K_EDIT);
331
				iniSetString(&inifile,itemname,"Address",item->addr,&ini_style);
332 333 334
				break;
			case 2:
				i=item->port;
335
				sprintf(str,"%hu",item->port);
336 337 338 339
				uifc.helpbuf=	"`Port`\n\n"
								"Enter the port which the BBS is listening to on the remote system\n"
								"Telnet is generally port 23 and RLogin is generally 513\n";
				uifc.input(WIN_MID|WIN_SAV,0,0,"Port",str,5,K_EDIT|K_NUMBER);
340 341
				j=atoi(str);
				if(j<1 || j>65535)
342
					j=conn_ports[item->conn_type];
343
				item->port=j;
344
				iniSetShortInt(&inifile,itemname,"Port",item->port,&ini_style);
345 346 347 348 349 350
				if(i!=j)
					uifc.changes=1;
				else
					uifc.changes=0;
				break;
			case 3:
deuce's avatar
deuce committed
351 352
				uifc.helpbuf=	"`Username`\n\n"
								"Enter the username to attempt auto-login to the remote with.";
353
				uifc.input(WIN_MID|WIN_SAV,0,0,"Username",item->user,MAX_USER_LEN,K_EDIT);
354
				iniSetString(&inifile,itemname,"UserName",item->user,&ini_style);
355 356
				break;
			case 4:
deuce's avatar
deuce committed
357 358
				uifc.helpbuf=	"`Password`\n\n"
								"Enter your password for auto-login.";
359
				uifc.input(WIN_MID|WIN_SAV,0,0,"Password",item->password,MAX_PASSWD_LEN,K_EDIT);
360
				iniSetString(&inifile,itemname,"Password",item->password,&ini_style);
361
				break;
deuce's avatar
deuce committed
362
			case 5:
363 364 365 366 367
				uifc.helpbuf=	"`System Password`\n\n"
								"Enter your System password for auto-login."
								"For non-Synchronet systems, or non-SysOp accounts,"
								"this can be used for simple scripting.";
				uifc.input(WIN_MID|WIN_SAV,0,0,"System Password",item->syspass,MAX_SYSPASS_LEN,K_EDIT);
368
				iniSetString(&inifile,itemname,"SystemPassword",item->syspass,&ini_style);
369 370
				break;
			case 6:
371 372 373 374
				item->conn_type--;
				uifc.helpbuf=	"`Connection Type`\n\n"
								"Select the type of connection you wish to make:\n"
								"~ RLogin:~ Auto-login with RLogin protocol\n"
375 376
								"~ Telnet:~ Use more common Telnet protocol\n"
								"~ Raw:   ~ Make a raw socket connection\n";
377
				uifc.list(WIN_SAV,0,0,0,&(item->conn_type),NULL,"Connection Type",&(conn_types[1]));
378
				item->conn_type++;
379
				iniSetEnum(&inifile,itemname,"ConnectionType",conn_types,item->conn_type,&ini_style);
380 381 382 383 384 385 386 387

				/* Set the port too */
				j=conn_ports[item->conn_type];
				if(j<1 || j>65535)
					j=item->port;
				item->port=j;
				iniSetShortInt(&inifile,itemname,"Port",item->port,&ini_style);

388
				changed=1;
deuce's avatar
deuce committed
389
				break;
390
			case 7:
391 392
				item->reversed=!item->reversed;
				changed=1;
393
				iniSetBool(&inifile,itemname,"Reversed",item->reversed,&ini_style);
394
				break;
395
			case 8:
396 397 398
				uifc.helpbuf=	"`Screen Mode`\n\n"
								"Select the screen size for this connection\n";
				uifc.list(WIN_SAV,0,0,0,&(item->screen_mode),NULL,"Screen Mode",screen_modes);
399
				iniSetEnum(&inifile,itemname,"ScreenMode",screen_modes,item->screen_mode,&ini_style);
400
				changed=1;
401
				break;
402
			case 9:
deuce's avatar
deuce committed
403 404
				item->nostatus=!item->nostatus;
				changed=1;
405
				iniSetBool(&inifile,itemname,"NoStatus",item->nostatus,&ini_style);
deuce's avatar
deuce committed
406
				break;
407
			case 10:
408 409 410
				uifc.helpbuf=	"`Download Path`\n\n"
								"Enter the path where downloads will be placed.";
				uifc.input(WIN_MID|WIN_SAV,0,0,"Download Path",item->dldir,MAX_PATH,K_EDIT);
411
				iniSetString(&inifile,itemname,"DownloadPath",item->dldir,&ini_style);
412
				break;
413
			case 11:
414 415 416
				uifc.helpbuf=	"`Upload Path`\n\n"
								"Enter the path where uploads will be browsed for.";
				uifc.input(WIN_MID|WIN_SAV,0,0,"Upload Path",item->uldir,MAX_PATH,K_EDIT);
417
				iniSetString(&inifile,itemname,"UploadPath",item->uldir,&ini_style);
418
				break;
419
			case 12:
420
				uifc.helpbuf=	"`Log Filename`\n\n"
421 422 423 424 425
								"Enter the path to the optional log file.";
				uifc.input(WIN_MID|WIN_SAV,0,0,"Log File",item->logfile,MAX_PATH,K_EDIT);
				iniSetString(&inifile,itemname,"LogFile",item->logfile,&ini_style);
				break;
			case 13:
426 427 428 429 430 431
				item->xfer_loglevel--;
				if(item->xfer_loglevel<0)
					item->xfer_loglevel=LOG_DEBUG;
				else if(item->xfer_loglevel<LOG_ERR)
					item->xfer_loglevel=0;
				iniSetEnum(&inifile,itemname,"TransferLogLevel",log_levels,item->xfer_loglevel,&ini_style);
432
				changed=1;
433
				break;
434
			case 14:
435 436 437 438 439 440 441 442 443
				item->telnet_loglevel--;
				if(item->telnet_loglevel<0)
					item->telnet_loglevel=LOG_DEBUG;
				else if(item->telnet_loglevel<LOG_ERR)
					item->telnet_loglevel=0;
				iniSetEnum(&inifile,itemname,"TelnetLogLevel",log_levels,item->telnet_loglevel,&ini_style);
				changed=1;
				break;
			case 15:
444 445 446 447 448 449
				uifc.helpbuf=	"`Simulated BPS Rate`\n\n"
								"Select the rate which recieved characters will be displayed.\n\n"
								"This allows ANSImation to work as intended.";
				i=get_rate_num(item->bpsrate);
				uifc.list(WIN_SAV,0,0,0,&i,NULL,"Simulated BPS Rate",rate_names);
				item->bpsrate=rates[i];
450
				iniSetInteger(&inifile,itemname,"BPSRate",item->bpsrate,&ini_style);
451
				changed=1;
452
				break;
453
			case 16:
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
				uifc.helpbuf="`ANSI Music Setup`\n\n"
						"~ ANSI Music Disabled ~ Completely disables ANSI music\n"
						"                      Enables Delete Line\n"
						"~ ESC[N ~               Enables BANSI-Style ANSI music\n"
						"                      Enables Delete Line\n"
						"~ ANSI Music Enabled ~  Enables both ESC[M and ESC[N ANSI music.\n"
						"                      Delete Line is disabled.\n"
						"\n"
						"So-Called ANSI Music has a long and troubled history.  Although the\n"
						"original ANSI standard has well defined ways to provide private\n"
						"extensions to the spec, none of these methods were used.  Instead,\n"
						"so-called ANSI music replaced the Delete Line ANSI sequence.  Many\n"
						"full-screen editors use DL, and to this day, some programs (Such as\n"
						"BitchX) require it to run.\n\n"
						"To deal with this, BananaCom decided to use what *they* though was an\n"
						"unspecified escape code ESC[N for ANSI music.  Unfortunately, this is\n"
						"broken also.  Although rarely implemented in BBS clients, ESC[N is\n"
						"the erase field sequence.\n\n"
						"SyncTERM has now defined a third ANSI music sequence which *IS* legal\n"
						"according to the ANSI spec.  Specifically ESC[|.";
				i=item->music;
				if(uifc.list(WIN_SAV,0,0,0,&i,NULL,"ANSI Music Setup",music_names)!=-1) {
					item->music=i;
477
					iniSetInteger(&inifile,itemname,"ANSIMusic",item->music,&ini_style);
478 479 480
					changed=1;
				}
				break;
481
			case 17:
deuce's avatar
deuce committed
482 483 484 485
				uifc.helpbuf=	"`Font`\n\n"
								"Select the desired font for this connection.\n\n"
								"Some fonts do not allow some modes.  When this is the case, 80x25 will be"
								"forced.\n";
486 487 488 489 490
				i=j=find_font_id(item->font);
				uifc.list(WIN_SAV,0,0,0,&i,&j,"Font",font_names);
				if(i!=find_font_id(item->font)) {
					strcpy(item->font,font_names[i]);
					iniSetString(&inifile,itemname,"Font",item->font,&ini_style);
deuce's avatar
deuce committed
491 492 493
					changed=1;
				}
				break;
494 495 496 497 498 499
		}
		if(uifc.changes)
			changed=1;
	}
}

500 501 502 503 504
void add_bbs(char *listpath, struct bbslist *bbs)
{
	FILE *listfile;
	str_list_t	inifile;

505 506
	if(safe_mode)
		return;
507 508 509 510 511 512 513 514 515 516 517
	if((listfile=fopen(listpath,"r"))!=NULL) {
		inifile=iniReadFile(listfile);
		fclose(listfile);
	}
	else {
		inifile=strListInit();
	}
	/* 
	 * Redundant:
	 * iniAddSection(&inifile,bbs->name,NULL);
	 */
518 519 520 521 522 523 524 525 526 527 528 529 530
	iniSetString(&inifile,bbs->name,"Address",bbs->addr,&ini_style);
	iniSetShortInt(&inifile,bbs->name,"Port",bbs->port,&ini_style);
	iniSetDateTime(&inifile,bbs->name,"Added",/* include time */TRUE,time(NULL),&ini_style);
	iniSetDateTime(&inifile,bbs->name,"LastConnected",/* include time */TRUE,bbs->connected,&ini_style);
	iniSetInteger(&inifile,bbs->name,"TotalCalls",bbs->calls,&ini_style);
	iniSetString(&inifile,bbs->name,"UserName",bbs->user,&ini_style);
	iniSetString(&inifile,bbs->name,"Password",bbs->password,&ini_style);
	iniSetString(&inifile,bbs->name,"SystemPassword",bbs->syspass,&ini_style);
	iniSetEnum(&inifile,bbs->name,"ConnectionType",conn_types,bbs->conn_type,&ini_style);
	iniSetBool(&inifile,bbs->name,"Reversed",bbs->reversed,&ini_style);
	iniSetEnum(&inifile,bbs->name,"ScreenMode",screen_modes,bbs->screen_mode,&ini_style);
	iniSetString(&inifile,bbs->name,"DownloadPath",bbs->dldir,&ini_style);
	iniSetString(&inifile,bbs->name,"UploadPath",bbs->uldir,&ini_style);
531
	iniSetString(&inifile,bbs->name,"LogFile",bbs->logfile,&ini_style);
532 533
	iniSetEnum(&inifile,bbs->name,"TransferLogLevel",log_levels,bbs->xfer_loglevel,&ini_style);
	iniSetEnum(&inifile,bbs->name,"TelnetLogLevel",log_levels,bbs->telnet_loglevel,&ini_style);
534
	iniSetInteger(&inifile,bbs->name,"BPSRate",bbs->bpsrate,&ini_style);
535
	iniSetInteger(&inifile,bbs->name,"ANSIMusic",bbs->music,&ini_style);
536
	iniSetString(&inifile,bbs->name,"Font",bbs->font,&ini_style);
537 538 539 540 541 542 543 544 545 546 547 548
	if((listfile=fopen(listpath,"w"))!=NULL) {
		iniWriteFile(listfile,inifile);
		fclose(listfile);
	}
	strListFreeStrings(inifile);
}

void del_bbs(char *listpath, struct bbslist *bbs)
{
	FILE *listfile;
	str_list_t	inifile;

549 550
	if(safe_mode)
		return;
551 552 553 554 555 556 557 558 559 560 561 562
	if((listfile=fopen(listpath,"r"))!=NULL) {
		inifile=iniReadFile(listfile);
		fclose(listfile);
		iniRemoveSection(&inifile,bbs->name);
		if((listfile=fopen(listpath,"w"))!=NULL) {
			iniWriteFile(listfile,inifile);
			fclose(listfile);
		}
		strListFreeStrings(inifile);
	}
}

563
void change_settings(void)
564
{
565
	char	inipath[MAX_PATH+1];
566 567
	FILE	*inifile;
	str_list_t	inicontents;
deuce's avatar
deuce committed
568 569
	char	opts[6][80];
	char	*opt[6];
570
	int		i,j;
571
	char	str[64];
deuce's avatar
deuce committed
572
	int	cur=0;
573 574 575

	get_syncterm_filename(inipath, sizeof(inipath), SYNCTERM_PATH_INI, FALSE);
	if((inifile=fopen(inipath,"r"))!=NULL) {
576
		inicontents=iniReadFile(inifile);
577 578 579
		fclose(inifile);
	}
	else {
580
		inicontents=strListInit();
581 582
	}

deuce's avatar
deuce committed
583
	for(i=0; i<6; i++)
584
		opt[i]=opts[i];
585

deuce's avatar
deuce committed
586
	opts[5][0]=0;
587
	for(;;) {
588 589 590
		sprintf(opts[0],"Confirm Program Exit    %s",settings.confirm_close?"Yes":"No");
		sprintf(opts[1],"Startup Video Mode      %s",screen_modes[settings.startup_mode]);
		sprintf(opts[2],"Scrollback Buffer Lines %d",settings.backlines);
deuce's avatar
deuce committed
591 592
		sprintf(opts[3],"Modem Device            %s",settings.mdm.device_name);
		sprintf(opts[4],"Modem Init String       %s",settings.mdm.init_string);
deuce's avatar
deuce committed
593
		switch(uifc.list(WIN_ACT|WIN_MID|WIN_SAV,0,0,0,&cur,NULL,"Program Settings",opt)) {
594 595 596 597 598
			case -1:
				goto write_ini;
			case 0:
				settings.confirm_close=!settings.confirm_close;
				iniSetBool(&inicontents,"SyncTERM","ConfirmClose",settings.confirm_close,&ini_style);
599
				break;
600 601
			case 1:
				j=settings.startup_mode;
deuce's avatar
deuce committed
602 603 604 605 606 607 608
				switch(i=uifc.list(WIN_SAV,0,0,0,&j,NULL,"Startup Video Mode",screen_modes)) {
					case -1:
						continue;
					default:
						settings.startup_mode=j;
						iniSetInteger(&inicontents,"SyncTERM","VideoMode",settings.startup_mode,&ini_style);
						break;
609
				}
610 611 612
				break;
			case 2:
				sprintf(str,"%d",settings.backlines);
deuce's avatar
deuce committed
613
				if(uifc.input(WIN_SAV|WIN_MID,0,0,"Scrollback Lines",str,9,K_NUMBER|K_EDIT)!=-1) {
614 615 616
					unsigned char *tmpscroll;

					j=atoi(str);
rswindell's avatar
rswindell committed
617
					if(j<1)
deuce's avatar
deuce committed
618
						uifc.msg("Cannot set lines to less than one.");
619
					else {
deuce's avatar
deuce committed
620 621 622 623 624
						tmpscroll=(unsigned char *)realloc(scrollback_buf,80*2*j);
						if(tmpscroll == NULL) {
							uifc.msg("Cannot allocate space for scrollback.");
						}
						else {
625
							if(scrollback_lines > (unsigned)j)
deuce's avatar
deuce committed
626 627 628 629 630
								scrollback_lines=j;
							scrollback_buf=tmpscroll;
							settings.backlines=j;
							iniSetInteger(&inicontents,"SyncTERM","ScrollBackLines",settings.backlines,&ini_style);
						}
631
					}
632 633
				}
				break;
deuce's avatar
deuce committed
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
			case 3:
				uifc.helpbuf=	"`Modem Device`\n\n"
#ifdef _WIN32
								"Enter the modem device name (ie: COM1).";
#else
								"Enter the modem device name (ie: /dev/ttyd0).";
#endif
				uifc.input(WIN_MID|WIN_SAV,0,0,"Modem Device",settings.mdm.device_name,LIST_NAME_MAX,K_EDIT);
				iniSetString(&inicontents,"SyncTERM","ModemDevice",settings.mdm.device_name,&ini_style);
				break;
			case 4:
				uifc.helpbuf=	"`Modem Init String`\n\n"
								"Your modem init string goes here.";
				uifc.input(WIN_MID|WIN_SAV,0,0,"Modem Init String",settings.mdm.init_string,LIST_NAME_MAX,K_EDIT);
				iniSetString(&inicontents,"SyncTERM","ModemInit",settings.mdm.init_string,&ini_style);
				break;
650 651
		}
	}
652
write_ini:
653 654 655 656 657
	if(!safe_mode) {
		if((inifile=fopen(inipath,"w"))!=NULL) {
			iniWriteFile(inifile,inicontents);
			fclose(inifile);
		}
658
	}
659 660
}

661 662 663 664
/*
 * Displays the BBS list and allows edits to user BBS list
 * Mode is one of BBSLIST_SELECT or BBSLIST_EDIT
 */
665
struct bbslist *show_bbslist(int mode)
666 667 668
{
	struct	bbslist	*list[MAX_OPTS+1];
	int		i,j;
669 670
	static int		opt=0,bar=0;
	int		oldopt=-1;
671
	int		sopt=0,sbar=0;
672 673 674
	static struct bbslist retlist;
	int		val;
	int		listcount=0;
675
	char	str[128];
676
	char	*YesNo[3]={"Yes","No",""};
677
	char	title[1024];
678
	char	*p;
679
	char	addy[LIST_ADDR_MAX+1];
680 681 682 683 684 685
	char	*settings_menu[]= {
					 "Default BBS Configuration"
					,"Mouse Actions"
					,"Screen Setup"
					,"Font Management"
					,"Program Settings"
686
					,NULL
687
				};
688
	int		at_settings=0;
689 690
	struct mouse_event mevent;
	struct bbslist defaults;
691 692
	char	shared_list[MAX_PATH+1];
	char	listpath[MAX_PATH+1];
693

694
	if(init_uifc(TRUE, TRUE))
695 696
		return(NULL);

697
	memset(list,0,sizeof(list));
698 699
	memset(&defaults,0,sizeof(defaults));

700
	get_syncterm_filename(listpath, sizeof(listpath), SYNCTERM_PATH_LIST, FALSE);
701
	read_list(listpath, list, &defaults, &listcount, USER_BBSLIST);
702 703

	/* System BBS List */
704
	get_syncterm_filename(shared_list, sizeof(shared_list), SYNCTERM_PATH_LIST, TRUE);
705 706
	if(stricmp(shared_list, listpath)) /* don't read the same list twice */
		read_list(shared_list, list, &defaults, &listcount, SYSTEM_BBSLIST);
707 708

	sort_list(list);
709 710 711
	uifc.helpbuf=	"`SyncTERM Settings Menu`\n\n";
	uifc.list(WIN_T2B|WIN_RHT|WIN_IMM|WIN_INACT
		,0,0,0,&sopt,&sbar,"SyncTERM Settings",settings_menu);
712
	for(;;) {
713 714
		if (!at_settings) {
			for(;!at_settings;) {
715 716 717 718 719 720 721 722 723 724 725
				uifc.helpbuf=	"`SyncTERM Dialing Directory`\n\n"
								"Commands:\n\n"
								"~ CTRL-D ~ Quick-dial a URL\n"
								"~ CTRL-E ~ to edit the selected entry\n"
								" ~ ENTER ~ to dial the selected entry";
				if(opt != oldopt) {
					if(list[opt]!=NULL && list[opt]->name[0]) {
						sprintf(title, "%s - %s (%d calls / Last: %s", syncterm_version, (char *)(list[opt]), list[opt]->calls, list[opt]->connected?ctime(&list[opt]->connected):"Never\n");
						p=strrchr(title, '\n');
						if(p!=NULL)
							*p=')';
726
					}
727 728 729 730 731 732 733 734 735 736 737 738 739
					else
						strcpy(title,syncterm_version);
					settitle(title);
				}
				oldopt=opt;
				val=uifc.list((listcount<MAX_OPTS?WIN_XTR:0)
					|WIN_ACT|WIN_INSACT|WIN_DELACT|WIN_UNGETMOUSE
					|WIN_T2B|WIN_INS|WIN_DEL|WIN_EDIT|WIN_EXTKEYS|WIN_DYN
					,0,0,0,&opt,&bar,mode==BBSLIST_SELECT?"Directory":"Edit",(char **)list);
				if(val==listcount)
					val=listcount|MSK_INS;
				if(val<0) {
					switch(val) {
740 741 742
						case -2-0x3000:	/* ALT-B - Scrollback */
							viewofflinescroll();
							break;
743 744
						case -2-CIO_KEY_MOUSE:	/* Clicked outside of window... */
							getmouse(&mevent);
745 746 747
						case -2-0x0f00:	/* Backtab */
						case -2-0x4b00:	/* Left Arrow */
						case -2-0x4d00:	/* Right Arrow */
748 749 750 751
						case -11:		/* TAB */
							uifc.list((listcount<MAX_OPTS?WIN_XTR:0)
								|WIN_T2B|WIN_IMM|WIN_INACT
								,0,0,0,&opt,&bar,mode==BBSLIST_SELECT?"Directory":"Edit",(char **)list);
752
							at_settings=!at_settings;
753 754
							break;
						case -7:		/* CTRL-E */
deuce's avatar
deuce committed
755 756 757 758 759 760 761 762 763
							if(list[opt]) {
								i=list[opt]->id;
								if(edit_list(list[opt],listpath,FALSE)) {
									sort_list(list);
									for(j=0;list[j]!=NULL && list[j]->name[0];j++) {
										if(list[j]->id==i)
											opt=j;
									}
									oldopt=-1;
764 765 766 767 768 769 770 771 772 773
								}
							}
							break;
						case -6:		/* CTRL-D */
							uifc.changes=0;
							uifc.helpbuf=	"`SyncTERM QuickDial`\n\n"
											"Enter a URL in the format [(rlogin|telnet)://][user[:password]@]domainname[:port]\n";
							uifc.input(WIN_MID|WIN_SAV,0,0,"BBS Address",addy,LIST_ADDR_MAX,0);
							memcpy(&retlist, &defaults, sizeof(defaults));
							if(uifc.changes) {
774
								parse_url(addy,&retlist,defaults.conn_type,FALSE);
775 776 777 778 779
								free_list(&list[0],listcount);
								return(&retlist);
							}
							break;
						case -1:		/* ESC */
780
							if(settings.confirm_close && !confirm("Are you sure you want to exit?",NULL))
781 782 783
								continue;
							free_list(&list[0],listcount);
							return(NULL);
784
					}
785 786 787 788 789 790 791 792 793
				}
				else if(val&MSK_ON) {
					switch(val&MSK_ON) {
						case MSK_INS:
							if(listcount>=MAX_OPTS) {
								uifc.helpbuf=	"`Max List size reached`\n\n"
												"The total combined size of loaded BBS lists is currently the highest\n"
												"Supported size.  You must delete entries before adding more.";
								uifc.msg("Max List size reached!");
794
								break;
795
							}
796 797 798 799 800 801 802
							if(safe_mode) {
								uifc.helpbuf=	"`Cannot edit list in safe mode`\n\n"
												"SyncTERM is currently running in safe mode.  This means you cannot add to the\n"
												"BBS list.";
								uifc.msg("Cannot edit list in safe mode");
								break;
							}
803 804 805 806
							listcount++;
							list[listcount]=list[listcount-1];
							list[listcount-1]=(struct bbslist *)malloc(sizeof(struct bbslist));
							memcpy(list[listcount-1],&defaults,sizeof(struct bbslist));
807
							list[listcount-1]->id=listcount-1;
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
							uifc.changes=0;
							uifc.helpbuf=	"`BBS Name`\n\n"
											"Enter the BBS name as it is to appear in the list.";
							uifc.input(WIN_MID|WIN_SAV,0,0,"BBS Name",list[listcount-1]->name,LIST_NAME_MAX,K_EDIT);
							if(uifc.changes) {
								uifc.changes=0;
								uifc.helpbuf=	"`Address`\n\n"
												"Enter the domain name of the system to connect to ie:\n"
												"nix.synchro.net";
								uifc.input(WIN_MID|WIN_SAV,0,0,"Address",list[listcount-1]->addr,LIST_ADDR_MAX,K_EDIT);
							}
							if(!uifc.changes) {
								free(list[listcount-1]);
								list[listcount-1]=list[listcount];
								listcount--;
							}
							else {
								add_bbs(listpath,list[listcount-1]);
								sort_list(list);
827
								for(j=0;list[j]!=NULL && list[j]->name[0];j++) {
828 829 830 831 832 833 834
									if(list[j]->id==listcount-1)
										opt=j;
								}
								oldopt=-1;
							}
							break;
						case MSK_DEL:
835
							if(list[opt]==NULL || !list[opt]->name[0]) {
836 837 838 839 840 841 842 843 844 845 846 847 848
								uifc.helpbuf=	"`Calming down`\n\n"
												"~ Some handy tips on calming down ~\n"
												"Close your eyes, imagine yourself alone on a brilliant white beach...\n"
												"Picture the palm trees up towards the small town...\n"
												"Glory in the deep blue of the perfectly clean ocean...\n"
												"Feel the plush comfort of your beach towel...\n"
												"Enjoy the shade of your satellite internet feed which envelops\n"
												"your head, keeping you cool...\n"
												"Set your TEMPEST rated laptop aside on the beach, knowing it's\n"
												"completely impervious to anything on the beach...\n"
												"Reach over to your fridge, grab a cold one...\n"
												"Watch the seagulls in their dance...\n";
								uifc.msg("It's gone, calm down man!");
849
								break;
850
							}
851 852 853 854 855 856 857
							if(safe_mode) {
								uifc.helpbuf=	"`Cannot edit list in safe mode`\n\n"
												"SyncTERM is currently running in safe mode.  This means you cannot remove from the\n"
												"BBS list.";
								uifc.msg("Cannot edit list in safe mode");
								break;
							}
858 859 860
							sprintf(str,"Delete %s?",list[opt]->name);
							i=1;
							if(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,NULL,str,YesNo)!=0)
861
								break;
862 863
							del_bbs(listpath,list[opt]);
							free(list[opt]);
864
							for(i=opt;list[i]!=NULL && list[i]->name[0];i++) {
865 866
								list[i]=list[i+1];
							}
867
							for(i=0;list[i]!=NULL && list[i]->name[0];i++) {
868 869 870 871 872 873
								list[i]->id=i;
							}
							listcount--;
							oldopt=-1;
							break;
						case MSK_EDIT:
874 875 876 877 878 879 880
							if(safe_mode) {
								uifc.helpbuf=	"`Cannot edit list in safe mode`\n\n"
												"SyncTERM is currently running in safe mode.  This means you cannot edit the\n"
												"BBS list.";
								uifc.msg("Cannot edit list in safe mode");
								break;
							}
881 882 883
							i=list[opt]->id;
							if(edit_list(list[opt],listpath,FALSE)) {
								sort_list(list);
884
								for(j=0;list[j]!=NULL && list[j]->name[0];j++) {
885 886 887 888 889 890
									if(list[j]->id==i)
										opt=j;
								}
								oldopt=-1;
							}
							break;
891
					}
892 893 894
				}
				else {
					if(mode==BBSLIST_EDIT) {
895 896 897 898 899 900 901
						if(safe_mode) {
							uifc.helpbuf=	"`Cannot edit list in safe mode`\n\n"
											"SyncTERM is currently running in safe mode.  This means you cannot edit the\n"
											"BBS list.";
							uifc.msg("Cannot edit list in safe mode");
							break;
						}
902 903 904
						i=list[opt]->id;
						if(edit_list(list[opt],listpath,FALSE)) {
							sort_list(list);
905
							for(j=0;list[j]!=NULL && list[j]->name[0];j++) {
906 907 908 909
								if(list[j]->id==i)
									opt=j;
							}
							oldopt=-1;
910 911
						}
					}
912 913 914 915 916 917
					else {
						memcpy(&retlist,list[val],sizeof(struct bbslist));
						free_list(&list[0],listcount);
						return(&retlist);
					}
				}
918 919 920
			}
		}
		else {
921
			for(;at_settings;) {
922 923 924 925 926 927 928
				uifc.helpbuf=	"`SyncTERM Settings Menu`\n\n";
				if(oldopt != -2)
					settitle(syncterm_version);
				oldopt=-2;
				val=uifc.list(WIN_ACT|WIN_T2B|WIN_RHT|WIN_EXTKEYS|WIN_DYN|WIN_UNGETMOUSE
					,0,0,0,&sopt,&sbar,"SyncTERM Settings",settings_menu);
				switch(val) {
929 930 931
					case -2-0x3000:	/* ALT-B - Scrollback */
						viewofflinescroll();
						break;
932 933
					case -2-CIO_KEY_MOUSE:
						getmouse(&mevent);
934 935 936
					case -2-0x0f00:	/* Backtab */
					case -2-0x4b00:	/* Left Arrow */
					case -2-0x4d00:	/* Right Arrow */
937 938 939
					case -11:		/* TAB */
						uifc.list(WIN_T2B|WIN_RHT|WIN_IMM|WIN_INACT
							,0,0,0,&sopt,&sbar,"SyncTERM Settings",settings_menu);
940
						at_settings=!at_settings;
941 942
						break;
					case -1:		/* ESC */
943
						if(settings.confirm_close && !confirm("Are you sure you want to exit?",NULL))
944 945 946 947 948 949
							continue;
						free_list(&list[0],listcount);
						return(NULL);
					case 0:			/* Edit default connection settings */
						edit_list(&defaults,listpath,TRUE);
						break;
950 951 952
					case 1:			/* Mouse Actions setup */
						uifc.msg("This section not yet functional");
						break;
deuce's avatar