1 /* TomeNET account editor - evileye */
2 /* Quick account editor for server admin
3    It can be made more visually attractive later maybe.
4    I just didn't want to leave accounts unchangeable
5    while testing. */
6 
7 #define HAVE_CRYPT 1
8 
9 #include <curses.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 #include <errno.h>
16 #include <sys/file.h>
17 
18 #include "account.h"
19 
20 #ifndef MIN
21 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
22 #endif
23 
24 static char *t_crypt(char *inbuf, const char *salt);
25 
26 void editor(void);
27 void edit(void);
28 unsigned short ask(char *prompt);
29 void status(char *info);
30 void setupscreen(void);
31 unsigned short recwrite(struct account *rec, long filepos);
32 int ListAccounts(int fpos);
33 void statinput(char *prompt, char *string, int max);
34 void getstring(const char *prompt, char *string, int max);
35 int findacc(void);
36 void purge_duplicates(void);
37 
38 FILE *fp;
39 WINDOW *listwin, *mainwin;
40 
41 char *fname = "tomenet.acc";
42 char newpass[20];
43 char *crypass;
44 
45 int tfpos;
46 
main()47 int main() {
48 	fp = fopen(fname, "rb");
49 	if (fp == (FILE*)NULL) {
50 		fprintf(stderr, "Cannot open %s\n", fname);
51 		exit(20);
52 	}
53 	editor();
54 	fclose(fp);
55 	return(0);
56 }
57 
setupscreen()58 void setupscreen() {
59 	attron(A_STANDOUT);
60 	move(0, 0);
61 	clrtoeol();
62 	mvprintw(0, COLS / 2 - 18, "TomeNET account editor - 2002 Evileye");
63 	mvprintw(1, COLS / 2 - 16, "(Updated by Mikaelh and C. Blue)");
64 	attroff(A_STANDOUT);
65 	mvprintw(LINES - 3, COLS / 2 - 19, "N: next      P: previous     D: Delete");
66 	mvprintw(LINES - 4, COLS / 2 - 19, "V: Validate A: Admin S: Score M: Multi");
67 	mvprintw(LINES - 5, COLS / 2 - 19, "L: List/Long F: Find");
68 	mainwin = newwin(LINES - 9, COLS, 3, 0);
69 	listwin = newwin(LINES - 9, COLS, 3, 0);
70 	refresh();
71 }
72 
recwrite(struct account * rec,long filepos)73 unsigned short recwrite(struct account *rec, long filepos) {
74 	int wfd;
75 #ifdef NETBSD
76 	wfd = open("tomenet.acc", O_RDWR|O_EXLOCK);	/* blocked open */
77 #else
78 	wfd = open("tomenet.acc", O_RDWR);
79 #endif
80 	if (wfd < 0) return(0);
81 #ifndef NETBSD
82 	if ((flock(wfd, LOCK_EX)) != 0) return(0);
83 #endif
84 	lseek(wfd, filepos, SEEK_SET);
85 	if (write(wfd, rec, sizeof(struct account)) == -1)
86 		fprintf(stderr, "write error occurred.");
87 #ifndef NETBSD
88 	while((flock(wfd, LOCK_UN)) != 0);
89 #endif
90 	close(wfd);
91 #ifdef NETBSD
92 	fpurge(fp);
93 #else
94 	fflush(fp);
95 #endif
96 	fseek(fp, filepos + sizeof(struct account), SEEK_SET);
97 	return(1);
98 }
99 
100 /* short form list editor */
ListAccounts(int fpos)101 int ListAccounts(int fpos) {
102 	int quit = 0;
103 	char ch;
104 	int ifpos = 0;	/* internal file (LIST TOP) position */
105 	int i = 0, x;
106 	short reload = 1;
107 	short redraw = 0;
108 	struct account c_acc;
109 	unsigned short change = 0;
110 
111 	touchwin(listwin);
112 	mvwaddstr(listwin, 0, 5, "Name");
113 	mvwaddstr(listwin, 0, 27, "Val");
114 	mvwaddstr(listwin, 0, 31, "Adm");
115 	mvwaddstr(listwin, 0, 35, "Sco");
116 	mvwaddstr(listwin, 0, 39, "Mul");
117 	mvwaddstr(listwin, 0, 43, "Res");
118 	mvwaddstr(listwin, 0, 47, "Pri");
119 	mvwaddstr(listwin, 0, 51, "PK");
120 	mvwaddstr(listwin, 0, 55, "Qui");
121 	mvwaddstr(listwin, 0, 59, "Ban");
122 	mvwaddstr(listwin, 0, 64, "Account ID");
123 	if (fpos > LINES-11) {
124 		ifpos = fpos - (LINES - 11);
125 	}
126 	while (!quit) {
127 		if (reload) {
128 			fseek(fp, ifpos*sizeof(struct account), SEEK_SET);
129 			for (i = 0; i < (LINES - 10); i++) {
130 				x = fread(&c_acc, sizeof(struct account), 1, fp);
131 				if (x == 0) break;
132 				mvwprintw(listwin, i+1, 5, "%-22s%-4c%-4c%-4c%-4c%-4c%-4c%-4c%-4c%-4c%.10d%10s", c_acc.name,
133 				c_acc.flags & ACC_TRIAL ? '.' : 'Y',
134 				c_acc.flags & ACC_ADMIN ? 'Y' : '.',
135 				c_acc.flags & ACC_NOSCORE ? '.' : 'Y',
136 				c_acc.flags & ACC_MULTI ? 'Y' : '.',
137 				c_acc.flags & ACC_VRESTRICTED ? 'V' : c_acc.flags & ACC_RESTRICTED ? 'Y' : '.',
138 				c_acc.flags & ACC_VPRIVILEGED ? 'V' : c_acc.flags & ACC_PRIVILEGED ? 'Y' : '.',
139 				c_acc.flags & ACC_PVP ? 'Y' : c_acc.flags & ACC_ANOPVP ? 'K' : c_acc.flags & ACC_NOPVP ? 'N' : '.',
140 				c_acc.flags & ACC_VQUIET ? 'V' : c_acc.flags & ACC_QUIET ? 'Y' : '.',
141 				c_acc.flags & ACC_BANNED ? 'Y' : '.',
142 				c_acc.id, c_acc.flags & ACC_DELD ? "DELETED" : "");
143 			}
144 			reload = 0;
145 			redraw = 1;
146 		}
147 		if (!change) {
148 			fseek(fp, fpos*sizeof(struct account), SEEK_SET);
149 			x = fread(&c_acc, sizeof(struct account), 1, fp);
150 		}
151 		if (redraw) {
152 			mvwprintw(listwin, (fpos - ifpos) + 1, 5, "%-22s%-4c%-4c%-4c%-4c%-4c%-4c%-4c%-4c%-4c%.10d%10s", c_acc.name,
153 			c_acc.flags & ACC_TRIAL ? '.' : 'Y',
154 			c_acc.flags & ACC_ADMIN ? 'Y' : '.',
155 			c_acc.flags & ACC_NOSCORE ? '.' : 'Y',
156 			c_acc.flags & ACC_MULTI ? 'Y' : '.',
157 			c_acc.flags & ACC_VRESTRICTED ? 'V' : c_acc.flags & ACC_RESTRICTED ? 'Y' : '.',
158 			c_acc.flags & ACC_VPRIVILEGED ? 'V' : c_acc.flags & ACC_PRIVILEGED ? 'Y' : '.',
159 			c_acc.flags & ACC_PVP ? 'Y' : c_acc.flags & ACC_ANOPVP ? 'K' : c_acc.flags & ACC_NOPVP ? 'N' : '.',
160 			c_acc.flags & ACC_VQUIET ? 'V' : c_acc.flags & ACC_QUIET ? 'Y' : '.',
161 			c_acc.flags & ACC_BANNED ? 'Y' : '.',
162 			c_acc.id, c_acc.flags & ACC_DELD ? "DELETED" : "");
163 			redraw = 0;
164 		}
165 		mvwaddch(listwin, (fpos - ifpos) + 1, 3, '>');
166 		wrefresh(listwin);
167 		ch = getch();
168 		move(LINES - 1, 0);
169 		clrtoeol();
170 		switch (ch) {
171 			case 'h':
172 			case 'H':
173 				getstring("New password: ", newpass, 20);
174 				crypass = t_crypt(newpass, c_acc.name);
175 				strncpy(c_acc.pass, crypass, 19);
176 				change = 1;
177 				break;
178 			case 'l':
179 			case 'L':
180 				quit = 1;
181 				break;
182 			case 'f':
183 			case 'F':
184 				mvwaddch(listwin, (fpos - ifpos) + 1, 3, ' ');
185 				if (change)
186 					if (ask("This record was changed. Save?")){
187 						if (recwrite(&c_acc, fpos * sizeof(struct account)))
188 							change = 0;
189 						else {
190 							if (!ask("Could not write record. Continue anyway?"))
191 								break;
192 						}
193 					}
194 				tfpos = findacc();
195 				if (tfpos >= 0) {
196 					fpos = tfpos;
197 					change = 0;
198 					if (fpos > ifpos + (LINES - 11))
199 						ifpos = fpos - (LINES - 11);
200 					else if (fpos < ifpos)
201 						ifpos = fpos;
202 					reload = 1;
203 				}
204 				break;
205 			case 'n':
206 			case 'N':
207 				if (change)
208 					if (ask("This record was changed. Save?")) {
209 						if (recwrite(&c_acc, fpos * sizeof(struct account)))
210 							change = 0;
211 						else {
212 							if (!ask("Could not write record. Continue anyway?"))
213 								break;
214 						}
215 					}
216 				mvwaddch(listwin, (fpos - ifpos) + 1, 3, ' ');
217 				if ((fpos - ifpos) < (i - 1)) {
218 					fpos++;
219 					change = 0;
220 				} else {
221 					if (i < (LINES - 11)) {
222 						status("There are no more records");
223 						break;
224 					}
225 					x = fread(&c_acc, sizeof(struct account), 1, fp);
226 					if (x == 0)
227 						status("There are no more records");
228 					else {
229 						ifpos++;
230 						fpos++;
231 						change = 0;
232 						reload = 1;
233 					}
234 				}
235 				break;
236 			case 'p':
237 			case 'P':
238 				if (change)
239 					if (ask("This record was changed. Save?")) {
240 						if (recwrite(&c_acc, fpos * sizeof(struct account)))
241 							change = 0;
242 						else {
243 							if (!ask("Could not write record. Continue anyway?"))
244 								break;
245 						}
246 					}
247 				mvwaddch(listwin, (fpos - ifpos) + 1, 3, ' ');
248 				if (fpos > ifpos) {
249 					fpos--;
250 					change = 0;
251 				} else {
252 					if (ifpos > 0) {
253 						ifpos--;
254 						fpos--;
255 						change = 0;
256 						reload = 1;
257 					}
258 					else
259 						status("This is the first record");
260 				}
261 				break;
262 			case 'q':
263 			case 'Q':
264 				if(ask("Are you sure you want to quit?")){
265 					quit = 1;
266 					fpos = -1;
267 				}
268 				break;
269 			case 'v':
270 			case 'V':
271 				change = 1;
272 				redraw = 1;
273 				c_acc.flags ^= ACC_TRIAL;
274 				break;
275 			case 'a':
276 			case 'A':
277 				change = 1;
278 				redraw = 1;
279 				c_acc.flags ^= ACC_ADMIN;
280 				break;
281 			case 'm':
282 			case 'M':
283 				change = 1;
284 				redraw = 1;
285 				c_acc.flags ^= ACC_MULTI;
286 				break;
287 			case 's':
288 			case 'S':
289 				change = 1;
290 				redraw = 1;
291 				c_acc.flags ^= ACC_NOSCORE;
292 				break;
293 			case 'c':
294 			case 'C':
295 				change = 1;
296 				if (c_acc.flags & ACC_VQUIET) {
297 					c_acc.flags &= ~(ACC_VQUIET | ACC_QUIET);
298 				} else if (c_acc.flags & ACC_QUIET) {
299 					c_acc.flags &= ~ACC_QUIET;
300 					c_acc.flags |= ACC_VQUIET;
301 				} else {
302 					c_acc.flags |= ACC_QUIET;
303 				}
304 				break;
305 			case 'b':
306 			case 'B':
307 				change = 1;
308 				c_acc.flags ^= ACC_BANNED;
309 				break;
310 			case 'k':
311 			case 'K':
312 				change = 1;
313 				if (c_acc.flags & ACC_ANOPVP) {
314 					c_acc.flags &= ~(ACC_ANOPVP | ACC_NOPVP);
315 				} else if (c_acc.flags & ACC_NOPVP) {
316 					c_acc.flags &= ~ACC_NOPVP;
317 					c_acc.flags |= ACC_ANOPVP;
318 				} else if (c_acc.flags & ACC_PVP) {
319 					c_acc.flags &= ~ACC_PVP;
320 					c_acc.flags |= ACC_NOPVP;
321 				} else {
322 					c_acc.flags |= ACC_PVP;
323 				}
324 				break;
325 			case 'r':
326 			case 'R':
327 				change = 1;
328 				if (c_acc.flags & ACC_VRESTRICTED) {
329 					c_acc.flags &= ~(ACC_VRESTRICTED | ACC_RESTRICTED);
330 				} else if (c_acc.flags & ACC_RESTRICTED) {
331 					c_acc.flags &= ~ACC_RESTRICTED;
332 					c_acc.flags |= ACC_VRESTRICTED;
333 				} else {
334 					c_acc.flags |= ACC_RESTRICTED;
335 				}
336 				break;
337 			case 'i':
338 			case 'I':
339 				change = 1;
340 				if (c_acc.flags & ACC_VPRIVILEGED) {
341 					c_acc.flags &= ~(ACC_VPRIVILEGED | ACC_PRIVILEGED);
342 				} else if (c_acc.flags & ACC_PRIVILEGED) {
343 					c_acc.flags &= ~ACC_PRIVILEGED;
344 					c_acc.flags |= ACC_VPRIVILEGED;
345 				} else {
346 					c_acc.flags |= ACC_PRIVILEGED;
347 				}
348 				break;
349 			case 'U':
350 				purge_duplicates();
351 				break;
352 			default:
353 				beep();
354 		}
355 	}
356 	mvwaddch(listwin, (fpos - ifpos) + 1, 3, ' ');
357 	return(fpos);
358 }
359 
editor()360 void editor() {
361 	int x;
362 	int quit = 0;
363 	char ch;
364 	unsigned long fpos = 0;
365 	struct account c_acc;
366 	unsigned short change = 0;
367 
368 	x = fread(&c_acc, sizeof(struct account), 1, fp);
369 	if (!x) {
370 		printf("Cannot read from file\n");
371 		return;
372 	}
373 
374 	initscr();
375 	cbreak();
376 	noecho();
377 	setupscreen();
378 
379 	while (!quit) {
380 		mvwprintw(mainwin, 0, 4, "%-30s   ID: %.10d", c_acc.name, c_acc.id);
381 		mvwprintw(mainwin, 1, 4, "%-20s             (%-30s)", c_acc.pass, c_acc.name_normalised);
382 		mvwprintw(mainwin, 3, 4, "Trial (inval): %-4s", c_acc.flags & ACC_TRIAL ? "Yes " : "No  ");
383 		mvwprintw(mainwin, 4, 4, "Administrator: %-4s", c_acc.flags & ACC_ADMIN ? "*** Yes *** " : "No          ");
384 		mvwprintw(mainwin, 5, 4, "Scoreboard:    %-4s", c_acc.flags & ACC_NOSCORE ? "No  " : "Yes ");
385 		mvwprintw(mainwin, 6, 4, "Multi-login:   %-4s", c_acc.flags & ACC_MULTI ? "Yes " : "No  ");
386 		mvwprintw(mainwin, 7, 4, "Restricted:    %-4s", c_acc.flags & ACC_VRESTRICTED ? "Very" : c_acc.flags & ACC_RESTRICTED ? "Yes " : "No  ");
387 		mvwprintw(mainwin, 8, 4, "Privileged:    %-3s", c_acc.flags & ACC_VPRIVILEGED ? "Very" : c_acc.flags & ACC_PRIVILEGED ? "Yes " : "No  ");
388 		mvwprintw(mainwin, 9, 4, "May pkill:     %-3s", c_acc.flags & ACC_PVP ? "Yes " : c_acc.flags & ACC_ANOPVP ? "_NO_" : c_acc.flags & ACC_NOPVP ? "No  " : "std.");
389 		mvwprintw(mainwin, 10, 4, "Muted chat:    %-3s", c_acc.flags & ACC_VQUIET ? "Very" : c_acc.flags & ACC_QUIET ? "Yes " : "No  ");
390 		mvwprintw(mainwin, 11, 4, "Banned:        %-3s", c_acc.flags & ACC_BANNED ? "** Yes ** " : "No        ");
391 		mvwprintw(mainwin, 3, 37, "%-7s", c_acc.flags & ACC_DELD ? "DELETED" : "");
392 		wrefresh(mainwin);
393 		do {
394 			ch = getch();
395 			move(LINES - 1, 0);
396 			clrtoeol();
397 			switch (ch) {
398 				case 'h':
399 				case 'H':
400 					getstring("New password: ", newpass, 20);
401 					crypass = t_crypt(newpass, c_acc.name);
402 					strncpy(c_acc.pass, crypass, 19);
403 					change = 1;
404 					break;
405 				case 'Q':
406 				case 'q':
407 					if (ask("Are you sure you want to quit?")){
408 						if (change)
409 							if (ask("This record was changed. Save?")){
410 								recwrite(&c_acc, fpos * sizeof(struct account));
411 							}
412 						quit = 1;
413 					}
414 					break;
415 				case 'l':
416 				case 'L':
417 					/* Short list of accounts */
418 					fpos = ListAccounts(fpos);
419 					if (fpos == (unsigned long) - 1){
420 						quit = 1;
421 						break;
422 					}
423 
424 					fseek(fp, fpos * sizeof(struct account), SEEK_SET);
425 					x = fread(&c_acc, sizeof(struct account),1, fp);
426 					change = 0;
427 					touchwin(mainwin);
428 					continue;
429 					break;
430 				case 'f':
431 				case 'F':
432 					if (change)
433 						if (ask("This record was changed. Save?")) {
434 							if (recwrite(&c_acc, fpos * sizeof(struct account)))
435 								change = 0;
436 							else {
437 								if (!ask("Could not write record. Continue anyway?"))
438 									break;
439 							}
440 						}
441 					tfpos = findacc();
442 					if (tfpos >= 0) {
443 						fpos = tfpos;
444 						change = 0;
445 						fseek(fp, fpos * sizeof(struct account), SEEK_SET);
446 						x = fread(&c_acc, sizeof(struct account),1, fp);
447 					}
448 				break;
449 				case 'n':
450 				case 'N':
451 					if (change)
452 						if (ask("This record was changed. Save?")){
453 							if (recwrite(&c_acc, fpos * sizeof(struct account)))
454 								change = 0;
455 							else {
456 								if (!ask("Could not write record. Continue anyway?"))
457 									break;
458 							}
459 						}
460 					x = fread(&c_acc, sizeof(struct account),1, fp);
461 					if (!x) {
462 						status("No more records to edit.");
463 						beep();
464 						break;
465 					}
466 					fpos++;
467 					change = 0;
468 					break;
469 				case 'p':
470 				case 'P':
471 					if (change)
472 						if (ask("This record was changed. Save?")){
473 							if (recwrite(&c_acc, fpos * sizeof(struct account)))
474 								change = 0;
475 							else {
476 								if (!ask("Could not write record. Continue anyway?"))
477 									break;
478 							}
479 						}
480 					if (!fpos) {
481 						status("This is the first record");
482 						break;
483 					}
484 					fpos--;
485 					fseek(fp, fpos * sizeof(struct account), SEEK_SET);
486 					x = fread(&c_acc, sizeof(struct account),1, fp);
487 					change = 0;
488 					break;
489 				case 'D':
490 					if (ask("Are you sure you wish to delete this record?")){
491 						change = 1;
492 						c_acc.flags |= ACC_DELD;
493 					}
494 					break;
495 				case 'v':
496 				case 'V':
497 					change = 1;
498 					c_acc.flags ^= ACC_TRIAL;
499 					break;
500 				case 'a':
501 				case 'A':
502 					change = 1;
503 					c_acc.flags ^= ACC_ADMIN;
504 					break;
505 				case 'm':
506 				case 'M':
507 					change = 1;
508 					c_acc.flags ^= ACC_MULTI;
509 					break;
510 				case 's':
511 				case 'S':
512 					change = 1;
513 					c_acc.flags ^= ACC_NOSCORE;
514 					break;
515 				case 'c':
516 				case 'C':
517 					change = 1;
518 					if (c_acc.flags & ACC_VQUIET) {
519 						c_acc.flags &= ~(ACC_VQUIET | ACC_QUIET);
520 					} else if (c_acc.flags & ACC_QUIET) {
521 						c_acc.flags &= ~ACC_QUIET;
522 						c_acc.flags |= ACC_VQUIET;
523 					} else {
524 						c_acc.flags |= ACC_QUIET;
525 					}
526 					break;
527 				case 'b':
528 				case 'B':
529 					change = 1;
530 					c_acc.flags ^= ACC_BANNED;
531 					break;
532 				case 'k':
533 				case 'K':
534 					change = 1;
535 					if (c_acc.flags & ACC_ANOPVP) {
536 						c_acc.flags &= ~(ACC_ANOPVP | ACC_NOPVP);
537 					} else if (c_acc.flags & ACC_NOPVP) {
538 						c_acc.flags &= ~ACC_NOPVP;
539 						c_acc.flags |= ACC_ANOPVP;
540 					} else if (c_acc.flags & ACC_PVP) {
541 						c_acc.flags &= ~ACC_PVP;
542 						c_acc.flags |= ACC_NOPVP;
543 					} else {
544 						c_acc.flags |= ACC_PVP;
545 					}
546 					break;
547 				case 'r':
548 				case 'R':
549 					change = 1;
550 					if (c_acc.flags & ACC_VRESTRICTED) {
551 						c_acc.flags &= ~(ACC_VRESTRICTED | ACC_RESTRICTED);
552 					} else if (c_acc.flags & ACC_RESTRICTED) {
553 						c_acc.flags &= ~ACC_RESTRICTED;
554 						c_acc.flags |= ACC_VRESTRICTED;
555 					} else {
556 						c_acc.flags |= ACC_RESTRICTED;
557 					}
558 					break;
559 				case 'i':
560 				case 'I':
561 					change = 1;
562 					if (c_acc.flags & ACC_VPRIVILEGED) {
563 						c_acc.flags &= ~(ACC_VPRIVILEGED | ACC_PRIVILEGED);
564 					} else if (c_acc.flags & ACC_PRIVILEGED) {
565 						c_acc.flags &= ~ACC_PRIVILEGED;
566 						c_acc.flags |= ACC_VPRIVILEGED;
567 					} else {
568 						c_acc.flags |= ACC_PRIVILEGED;
569 					}
570 					break;
571 				case 'U':
572 					purge_duplicates();
573 					break;
574 				default:
575 					ch = ' ';
576 					beep();
577 			}
578 		} while (ch == ' ');
579 	}
580 	echo();
581 	nocbreak();
582 	endwin();
583 }
584 
585 /* account finder */
findacc()586 int findacc() {
587 	int x, i = 0;
588 	char sname[30];
589 	struct account c_acc;
590 
591 	statinput("Find which name: ", sname, 30);
592 	fseek(fp, 0L, SEEK_SET);
593 	/* its always upper, and admins can be lazy */
594 	sname[0] = toupper(sname[0]);
595 	while ((x = fread(&c_acc, sizeof(struct account),1, fp))) {
596 		if (!strncmp(c_acc.name, sname, 30)) {
597 			return(i);
598 		}
599 		i++;
600 	} while(x);
601 	status("Could not find that account");
602 
603 	return(-1);
604 }
605 
status(char * info)606 void status(char *info) {
607 	mvprintw(LINES - 1, 0, info);
608 	beep();
609 }
610 
statinput(char * prompt,char * string,int max)611 void statinput(char *prompt, char *string, int max) {
612 	char ch;
613 	int pos = 0;
614 	mvprintw(LINES - 1, 0, prompt);
615 	do {
616 		ch = getch();
617 		if (ch == '\n') break;
618 		if (ch == '\b') {
619 			if (pos) {
620 				string[--pos] = '\0';
621 				mvdelch(LINES - 1, strlen(prompt) + pos);
622 			}
623 			else
624 				beep();
625 		}
626 		else{
627 			if (pos < (max - 1)) {
628 				string[pos++] = ch;
629 				addch(ch);
630 			}
631 			else
632 				beep();
633 		}
634 		refresh();
635 	} while (ch != '\n');
636 	string[pos] = '\0';
637 	move(LINES - 1, 0);
638 	clrtoeol();
639 }
640 
getstring(const char * prompt,char * string,int max)641 void getstring(const char *prompt, char *string, int max) {
642 	char ch;
643 	int i = 0;
644 	mvprintw(LINES - 1, 0, prompt);
645 	do {
646 		ch = getch();
647 		if (ch == '\b' && i > 0)
648 			i--;
649 		if (ch == '\r' || ch == '\n') {
650 			string[i] = '\0';
651 			move(LINES - 1, 0);
652 			clrtoeol();
653 			return;
654 		}
655 		else {
656 			string[i++] = ch;
657 			addch(ch);
658 			if (i == max) {
659 				string[i] = '\0';
660 				move(LINES - 1, 0);
661 				clrtoeol();
662 				return;
663 			}
664 		}
665 	} while(1);
666 }
667 
668 /* our password encryptor */
t_crypt(char * inbuf,const char * salt)669 static char *t_crypt(char *inbuf, const char *salt) {
670 #ifdef HAVE_CRYPT
671 	static char out[64];
672  #if 0 /* doesn't do anything */
673 	char setting[9];
674 	setting[0] = '_';
675 	strncpy(&setting[1], salt, 8);
676  #endif
677   #if 1 /* fix for len-1 names */
678 	char setting[3];
679 	/* only 1 character long salt? expand to 2 chars length */
680 	if (!salt[1]) {
681 		setting[0] = '.';
682 		setting[1] = salt[0];
683 		setting[2] = 0;
684 		strcpy(out, (char*)crypt(inbuf, setting));
685 	} else
686  #endif
687  #if 1 /* SPACE _ ! - ' , and probably more as _2nd character_ cause crypt() to return a null pointer ('.' is ok) */
688   #define ACCOUNTNAME_LEN 16
689 	if (!((salt[1] >= 'A' && salt[1] <= 'Z') ||
690 	    (salt[1] >= 'a' && salt[1] <= 'z') ||
691 	    (salt[1] >= '0' && salt[1] <= '9') ||
692 	    salt[1] == '.')) {
693 		char fixed_name[ACCOUNTNAME_LEN];
694 		strcpy(fixed_name, salt);
695 		fixed_name[1] = '.';
696 		strcpy(out, (char*)crypt(inbuf, fixed_name));
697 	} else
698  #endif
699 	strcpy(out, (char*)crypt(inbuf, salt));
700 	return(out);
701 #else
702 	return(inbuf);
703 #endif
704 }
705 
ask(char * prompt)706 unsigned short ask(char *prompt) {
707 	char ch;
708 	mvprintw(LINES - 1, 0, prompt);
709 	do {
710 		ch = getch();
711 		if (ch == 'Y' || ch == 'y') break;
712 		if (ch == 'N' || ch == 'n') break;
713 	} while(1);
714 	move(LINES - 1, 0);
715 	clrtoeol();
716 	return ((ch == 'Y' || ch == 'y'));
717 }
718 
purge_duplicates(void)719 void purge_duplicates(void) {
720 	//char accname[];
721 }
722