1 /*
2  *	binkleyforce -- unix FTN mailer project
3  *
4  *	Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11
5  *
6  *	This program is free software; you can redistribute it and/or modify
7  *	it under the terms of the GNU General Public License as published by
8  *	the Free Software Foundation; either version 2 of the License, or
9  *	(at your option) any later version.
10  *
11  *	$Id: sess_main.c,v 1.1.1.1 2004/09/09 09:52:39 kstepanenkov Exp $
12  */
13 
14 #include "includes.h"
15 #include "confread.h"
16 #include "logger.h"
17 #include "bforce.h"
18 #include "util.h"
19 #include "nodelist.h"
20 #include "session.h"
21 #include "prot_zmodem.h"
22 #include "prot_yoohoo.h"
23 #include "prot_emsi.h"
24 #include "prot_binkp.h"
25 
26 /* All session information stores here */
27 s_state state;
28 
29 int hydra(s_protinfo *pi, bool flag_RH1);
30 
session_get_bestaka(s_faddr addr)31 s_faddr *session_get_bestaka(s_faddr addr)
32 {
33 	s_cval_entry *addr_ptr;
34 	s_cval_entry *hide_ptr;
35 	s_faddr *best = NULL;
36 	int bestl = 0;
37 	int curl = 0;
38 
39 	for( addr_ptr = conf_first(cf_address); addr_ptr;
40 	     addr_ptr = conf_next(addr_ptr) )
41 	{
42 		for( hide_ptr = conf_first(cf_hide_our_aka); hide_ptr;
43 		     hide_ptr = conf_next(hide_ptr) )
44 		{
45 			if( !ftn_addrcomp(hide_ptr->d.falist.addr, addr_ptr->d.falist.addr) )
46 				break;
47 		}
48 
49 		if( !hide_ptr )
50 		{
51 			curl = ftn_addrsmetric(addr_ptr->d.falist.addr, addr);
52 
53 			if( curl > bestl || best == NULL )
54 			{
55 				bestl = curl;
56 				best  = &addr_ptr->d.falist.addr;
57 			}
58 		}
59 	}
60 
61 	return best;
62 }
63 
session_addrs_lock(s_sysaddr * addrs,int anum)64 int session_addrs_lock(s_sysaddr *addrs, int anum)
65 {
66 	int i;
67 	char abuf[BF_MAXADDRSTR+1];
68 	bool one_lock = FALSE;
69 
70 	for( i = 0; i < anum; i++ )
71 	{
72 		if( addrs[i].good )
73 		{
74 #ifdef BFORCE_USE_CSY
75 			if( out_bsy_lock(addrs[i].addr, FALSE) )
76 #else
77 			if( out_bsy_lock(addrs[i].addr) )
78 #endif
79 			{
80 				bf_log("exclude address %s: allready locked",
81 					ftn_addrstr(abuf, addrs[i].addr));
82 				addrs[i].busy = TRUE;
83 			}
84 			else
85 				one_lock = TRUE;
86 		}
87 	}
88 
89 	return one_lock ? 0 : -1;
90 }
91 
session_addrs_add(s_sysaddr ** addrs,int * anum,s_faddr addr)92 int session_addrs_add(s_sysaddr **addrs, int *anum, s_faddr addr)
93 {
94 	int i;
95 	char abuf[BF_MAXADDRSTR+1];
96 
97 	if( *anum && *addrs )
98 	{
99 		/* Check for addresses duplication */
100 		for( i = 0; i < *anum; i++ )
101 		{
102 			if( !ftn_addrcomp((*addrs)[i].addr, addr) )
103 			{
104 				bf_log("exclude address %s: duplicated address",
105 					ftn_addrstr(abuf, addr));
106 				return -1;
107 			}
108 		}
109 	}
110 
111 	if( *addrs && *anum )
112 		*addrs = xrealloc(*addrs, sizeof(s_sysaddr)*(*anum+1));
113 	else
114 		*addrs = xmalloc(sizeof(s_sysaddr));
115 
116 	memset(&(*addrs)[*anum], '\0', sizeof(s_sysaddr));
117 
118 	(*addrs)[*anum].addr = addr;
119 	(*addrs)[*anum].busy = FALSE;
120 	(*addrs)[*anum].good = FALSE;
121 
122 	++(*anum);
123 
124 	return 0;
125 }
126 
session_addrs_check(s_sysaddr * addrs,int anum,const char * passwd,const char * challenge,int challenge_length)127 int session_addrs_check(s_sysaddr *addrs, int anum, const char *passwd,
128                         const char *challenge, int challenge_length)
129 {
130 	int i;
131 	char abuf[BF_MAXADDRSTR+1];
132 	char pbuf[32];
133 	bool failure = FALSE;
134 	bool success = FALSE;
135 	bool cram = (challenge && *challenge);
136 
137 	if( !anum )
138 		return -1;
139 
140 	for( i = 0; i < anum; i++ )
141 	{
142 		if( session_check_addr(addrs[i].addr) )
143 		{
144 			bf_log("exclude address %s: not acceptable",
145 				ftn_addrstr(abuf, addrs[i].addr));
146 			continue;
147 		}
148 
149 		if( !session_get_password(addrs[i].addr, pbuf, sizeof(pbuf)) )
150 		{
151 			bool good_passwd = FALSE;
152 
153 			if( passwd && *passwd )
154 			{
155 				if( cram )
156 				{
157 					char digest_bin[16];
158 					char digest_hex[33];
159 
160 					md5_cram_get(pbuf, challenge, challenge_length, digest_bin);
161 
162 					/* Encode digest to the hex string */
163 					string_bin_to_hex(digest_hex, digest_bin, 16);
164 
165 					if( strcasecmp(passwd, digest_hex) == 0 )
166 						good_passwd = TRUE;
167 				}
168 				else if( strcasecmp(passwd, pbuf) == 0 )
169 					good_passwd = TRUE;
170 			}
171 
172 			if( good_passwd )
173 			{
174 				/* correct password */
175 				addrs[i].good = TRUE;
176 				state.protected = TRUE;
177 				success = TRUE;
178 			}
179 			else
180 			{
181 				bf_log("exclude address %s: bad password",
182 					ftn_addrstr(abuf, addrs[i].addr));
183 				addrs[i].good = FALSE;
184 				failure = TRUE;
185 			}
186 		}
187 		else
188 			/* not password protected address */
189 			addrs[i].good = TRUE;
190 	}
191 
192 	/*
193 	 * Return error, if received password is incorrect for all AKAs
194 	 */
195 	if( failure && !success )
196 		return -1;
197 
198 	return 0;
199 }
200 
session_addrs_to_falist(s_sysaddr * addrs,int anum,s_falist ** dest)201 int session_addrs_to_falist(s_sysaddr *addrs, int anum, s_falist **dest)
202 {
203 	int i;
204 
205 	for( i = 0; i < anum; i++ )
206 	{
207 		if( !addrs[i].busy && addrs[i].good )
208 		{
209 			(*dest) = (s_falist *)xmalloc(sizeof(s_falist));
210 			memset(*dest, '\0', sizeof(s_falist));
211 			(*dest)->addr = addrs[i].addr;
212 			dest = (s_falist**)&((*dest)->next);
213 		}
214 	}
215 
216 	return 0;
217 }
218 
session_addrs_check_genuine(s_sysaddr * addrs,int anum,s_faddr expected)219 int session_addrs_check_genuine(s_sysaddr *addrs, int anum, s_faddr expected)
220 {
221 	int i;
222 
223 	for( i = 0; i < anum; i++ )
224 	{
225 		if( !ftn_addrcomp(addrs[i].addr, expected) )
226 			return 0;
227 	}
228 
229 	return 1;
230 }
231 
232 /* ------------------------------------------------------------------------- */
233 /* Return non-zero value if current speed too low                            */
234 /* ------------------------------------------------------------------------- */
session_check_speed(void)235 int session_check_speed(void)
236 {
237 	state.minspeed = conf_number(cf_min_speed_in);
238 
239 	if( state.connspeed > 0 && state.minspeed > state.connspeed )
240 		return 1;
241 
242 	return 0;
243 }
244 
session_check_addr(s_faddr addr)245 int session_check_addr(s_faddr addr)
246 {
247 	s_cval_entry *addr_ptr;
248 
249 	for( addr_ptr = conf_first(cf_address); addr_ptr;
250 	     addr_ptr = conf_next(addr_ptr) )
251 	{
252 		if( !ftn_addrcomp(addr, addr_ptr->d.falist.addr) )
253 			return 1;
254 	}
255 
256 	return 0;
257 }
258 
259 /* ------------------------------------------------------------------------- */
260 /* Get session password for address $addr, put it in $buf                    */
261 /* If no password found - return non-zero value                              */
262 /* ------------------------------------------------------------------------- */
session_get_password(s_faddr addr,char * buffer,size_t buflen)263 int session_get_password(s_faddr addr, char *buffer, size_t buflen)
264 {
265 	s_cval_entry *pwd_ptr;
266 
267 	for( pwd_ptr = conf_first(cf_password); pwd_ptr;
268 	     pwd_ptr = conf_next(pwd_ptr) )
269 	{
270 		if( !ftn_addrcomp(addr, pwd_ptr->d.falist.addr) )
271 		{
272 			strnxcpy(buffer, pwd_ptr->d.falist.what, buflen);
273 			return 0;
274 		}
275 	}
276 
277 	return 1;
278 }
279 
session_remote_lookup(s_sysaddr * addrs,int anum)280 int session_remote_lookup(s_sysaddr *addrs, int anum)
281 {
282 	int i;
283 
284 	for( i = 0; i < anum; i++ )
285 	{
286 		if( addrs[i].good )
287 		{
288 			nodelist_lookup(&state.node, addrs[i].addr);
289 			state.node.addr.domain[0] = '\0';
290 			state.listed = state.node.listed;
291 			break;
292 		}
293 	}
294 
295 	return (i < anum) ? 0 : -1;
296 }
297 
session_remote_log_status(void)298 void session_remote_log_status(void)
299 {
300 	bf_log("remote is %s,%s",
301 		(state.listed) ? "listed" : "unlisted",
302 		(state.protected) ? "protected" : "unprotected");
303 }
304 
305 /* ------------------------------------------------------------------------- */
306 /* Set inbound directory, create temporary inbound in it, check permissions  */
307 /* If something wrong - return non-zero value                                */
308 /* ------------------------------------------------------------------------- */
session_set_inbound(void)309 int session_set_inbound(void)
310 {
311 	struct stat st;
312 	char *p_inb;
313 
314 	if( (p_inb = conf_string(cf_inbound_directory)) )
315 	{
316 		state.inbound = (char*)xstrcpy(p_inb);
317 	}
318 	else
319 	{
320 		bf_log("no inbound specified, assume \"./\"");
321 		state.inbound = (char*)xstrcpy("./");
322 	}
323 
324 	state.tinbound = (char*)xstrcpy(state.inbound);
325 	state.tinbound = (char*)xstrcat(state.tinbound, "tmp/");
326 
327 	/*
328 	 * Warning, access() make checks using real uid and gid
329 	 * (not effective), so we can fail, but..
330 	 */
331 	if( stat(state.tinbound, &st) == 0 )
332 	{
333 		if( (st.st_mode & S_IFDIR) != S_IFDIR )
334 		{
335 			bf_log("temporary inbound \"%s\" is not directory", state.tinbound);
336 			return(1);
337 		}
338 		else if( access(state.tinbound, R_OK|W_OK|X_OK) )
339 		{
340 			bf_log("have no r/w permission to temporary inbound \"%s\"", state.tinbound);
341 			return(1);
342 		}
343 	}
344 	else if( errno == ENOENT )
345 	{
346 		/* "tmp" inbound doesn't exist */
347 		if( mkdir(state.tinbound, 0700) < 0 )
348 		{
349 			logerr("can't create temporary inbound \"%s\"", state.tinbound);
350 			return(1);
351 		}
352 		chmod(state.tinbound, 0700);
353 	}
354 	else
355 	{
356 		/* Different stat() errors */
357 		logerr("can't stat temporary inbound \"%s\"", state.tinbound);
358 		return 1;
359 	}
360 
361 	return(0);
362 }
363 
364 /* ------------------------------------------------------------------------- */
365 /* Set status of _OUR_ FREQ processor                                        */
366 /* ------------------------------------------------------------------------- */
session_set_freqs_status(void)367 void session_set_freqs_status(void)
368 {
369 	int root_ok = 0;
370 	int magc_ok = 0;
371 	char *p;
372 	long options;
373 
374 	state.reqstat = REQS_DISABLED;
375 
376 	options = conf_options(cf_options);
377 
378 	if( (options & OPTIONS_MAILONLY) == OPTIONS_MAILONLY
379 	 || (options & OPTIONS_NO_FREQS) == OPTIONS_NO_FREQS )
380 		{ state.reqstat = REQS_NOTALLOW; return; }
381 
382 	if( state.connspeed > 0
383 	 && state.connspeed < conf_number(cf_freq_min_speed) )
384 		{ state.reqstat = REQS_NOTALLOW; return; }
385 
386 	if( (p = conf_string(cf_freq_srif_command)) && *p )
387 	{
388 		/*
389 		 * Can we execute this processor? Disable freqs if we can't!
390 		 */
391 		if( !exec_file_exist(p) )
392 			state.reqstat = REQS_ALLOW;
393 		else
394 			logerr("can't stat SRIF processor \"%s\"", p);
395 	}
396 	else
397 	{
398 		/* Check root dir */
399 		if( (p = conf_string(cf_freq_dir_list)) && *p )
400 		{
401 			if( access(p, R_OK) == 0 )
402 				root_ok = 1;
403 			else
404 				logerr("can't stat FREQ dir list \"%s\"", p);
405 		}
406 
407 		/* Check magic dir */
408 		if( (p = conf_string(cf_freq_alias_list)) && *p )
409 		{
410 			if( access(p, R_OK) == 0 )
411 				magc_ok = 1;
412 			else
413 				logerr("can't stat FREQ alias list \"%s\"", p);
414 		}
415 
416 		/* Set FREQ processor status */
417 		if( root_ok || magc_ok )
418 			state.reqstat = REQS_ALLOW;
419 	}
420 }
421 
422 /* ------------------------------------------------------------------------- */
423 /* Set our "send options" (common part, based on our local settings)         */
424 /* ------------------------------------------------------------------------- */
session_set_send_options(void)425 void session_set_send_options(void)
426 {
427 	const long options = conf_options(cf_options);
428 
429 	if( state.caller == FALSE )
430 		state.sopts.holdreq = 1;
431 
432 	if( (options & OPTIONS_MAILONLY) == OPTIONS_MAILONLY )
433 		state.sopts.holdxt = 1;
434 	if( (options & OPTIONS_HOLDXT) == OPTIONS_HOLDXT )
435 		state.sopts.holdxt = 1;
436 	if( (options & OPTIONS_HOLDREQ) == OPTIONS_HOLDREQ )
437 		state.sopts.holdreq = 1;
438 	if( (options & OPTIONS_HOLDALL) == OPTIONS_HOLDALL )
439 		state.sopts.holdall = 1;
440 	if( (options & OPTIONS_HOLDHOLD) == OPTIONS_HOLDHOLD )
441 		state.sopts.holdhold = 1;
442 }
443 
444 /* ------------------------------------------------------------------------- */
445 /* Return (non-zero) if we _CAN'T_ send this file NOW!                       */
446 /* ------------------------------------------------------------------------- */
holdfile(s_filelist * fi,const char * delayout)447 static int holdfile(s_filelist *fi, const char *delayout)
448 {
449 	if( state.sopts.holdall                               ) return(1);
450 	if( state.sopts.holdxt  && !(fi->type & TYPE_NETMAIL) ) return(1);
451 	if( state.sopts.holdreq &&  (fi->type & TYPE_REQUEST) ) return(1);
452 	if( state.sopts.holdhold && fi->flavor == FLAVOR_HOLD ) return(1);
453 	if( fi->status != STATUS_WILLSEND                     ) return(1);
454 	if( delayout && !checkmasks(delayout, fi->fname)      ) return(2);
455 
456 	return 0;
457 }
458 
459 /* ------------------------------------------------------------------------- */
460 /* Set SKIP flag for files we can't send NOW                                 */
461 /* ------------------------------------------------------------------------- */
session_set_send_files(void)462 void session_set_send_files(void)
463 {
464 	int holdmsg = 0, rc = 0;
465 	s_filelist *ptrl = NULL;
466 
467 	const char *delayout = conf_string(cf_delay_files_send);
468 
469 	for( ptrl = state.queue.fslist; ptrl; ptrl = ptrl->next )
470 		if( (rc = holdfile(ptrl, delayout)) )
471 		{
472 			if( rc == 2 && !holdmsg )
473 			{
474 				bf_log("delaying files \"%s\"", delayout);
475 				++holdmsg;
476 			}
477 			ptrl->status = STATUS_SKIP;
478 		}
479 }
480 
session_create_files_queue(s_sysaddr * addrs,int anum)481 int session_create_files_queue(s_sysaddr *addrs, int anum)
482 {
483 	s_falist *mailfor = NULL;
484 	s_outbound_callback_data ocb;
485 
486 	/* Set addresses for which we will send files */
487 	(void)session_addrs_to_falist(addrs, anum, &mailfor);
488 
489 	/* Scan outbound directory */
490 	if( mailfor )
491 	{
492 		memset(&ocb, '\0', sizeof(s_outbound_callback_data));
493 		ocb.callback = out_handle_fsqueue;
494 		ocb.dest = (void *)&state.queue;
495 		(void)out_scan(&ocb, mailfor);
496 		(void)session_set_send_files();
497 		(void)session_traffic_set_outgoing(&state.traff_send);
498 	}
499 
500 	return 0;
501 }
502 
session_traffic_set_incoming(s_traffic * dest)503 int session_traffic_set_incoming(s_traffic *dest)
504 {
505 	memset(dest, '\0', sizeof(s_traffic));
506 
507 	if( state.handshake && state.handshake->remote_traffic )
508 		return state.handshake->remote_traffic(state.handshake, dest);
509 
510 	return -1;
511 }
512 
session_traffic_set_outgoing(s_traffic * dest)513 int session_traffic_set_outgoing(s_traffic *dest)
514 {
515 	s_filelist *ptrl;
516 
517 	memset(dest, '\0', sizeof(s_traffic));
518 
519 	for( ptrl = state.queue.fslist; ptrl; ptrl = ptrl->next )
520 	{
521 		if( ptrl->type & TYPE_NETMAIL )
522 		{
523 			dest->netmail_size += ptrl->size;
524 			dest->netmail_num++;
525 		}
526 		else if( ptrl->type & TYPE_ARCMAIL )
527 		{
528 			dest->arcmail_size += ptrl->size;
529 			dest->arcmail_num++;
530 		}
531 		else
532 		{
533 			dest->files_size += ptrl->size;
534 			dest->files_num++;
535 		}
536 	}
537 
538 	return 0;
539 }
540 
session_traffic_bf_log(bool incoming,s_traffic * traff)541 void session_traffic_bf_log(bool incoming, s_traffic *traff)
542 {
543 	char buf[32];
544 	char msg[128] = "";
545 
546 	if( traff == NULL )
547 		strcpy(msg, "unknown");
548 	else if( traff->netmail_size == 0
549 	      && traff->arcmail_size == 0 && traff->files_size == 0 )
550 		strcpy(msg, "none");
551 	else
552 	{
553 		if( traff->netmail_size > 0 )
554 		{
555 			string_humansize(buf, traff->netmail_size);
556 			strcat(msg, buf);
557 			strcat(msg, " netmail, ");
558 		}
559 		if( traff->arcmail_size > 0 )
560 		{
561 			string_humansize(buf, traff->arcmail_size);
562 			strcat(msg, buf);
563 			strcat(msg, " arcmail, ");
564 		}
565 		if( traff->files_size > 0 )
566 		{
567 			string_humansize(buf, traff->files_size);
568 			strcat(msg, buf);
569 			strcat(msg, " files, ");
570 		}
571 		if( *msg )
572 			msg[strlen(msg)-2] = '\0';
573 	}
574 
575 	bf_log("%s traffic: %s", incoming ? "incoming" : "outgoing", msg);
576 }
577 
session_traffic(void)578 void session_traffic(void)
579 {
580 	int rc;
581 
582 	rc = session_traffic_set_incoming(&state.traff_recv);
583 	session_traffic_bf_log(TRUE,  rc ? NULL : &state.traff_recv);
584 
585 	/* Outgoing traffic must be allread calculated */
586 	session_traffic_bf_log(FALSE, &state.traff_send);
587 }
588 
589 /*
590  * History file line format:
591  *   line verbal name,
592  *   remote address,
593  *   session start time (Unix),
594  *   session_length (seconds),
595  *   session status flags (L - listed, P - protected),
596  *   session result code (one of mailer return codes),
597  *   size of sent netmail,
598  *   size of sent arcmail,
599  *   size of sent files,
600  *   size of received netmail,
601  *   size of received arcmail,
602  *   size of received files
603  */
session_update_history(s_traffic * send,s_traffic * recv,int rc)604 void session_update_history(s_traffic *send, s_traffic *recv, int rc)
605 {
606 	FILE *hist_fp;
607 	char *hist_file = conf_string(cf_history_file);
608 	char  abuf[BFORCE_MAX_ADDRSTR+1];
609 	char  session_status[32] = "";
610 
611 	if( !hist_file )
612 		return;
613 
614 	hist_fp = file_open(hist_file, "a");
615 	if( !hist_fp )
616 	{
617 		logerr("cannot open history file \"%s\"", hist_file);
618 		return;
619 	}
620 
621 
622 	if( state.listed )
623 		strcat(session_status, "L");
624 	if( state.protected )
625 		strcat(session_status, "P");
626 	if( state.caller )
627 		strcat(session_status, "O");
628 	else
629 		strcat(session_status, "I");
630 
631 	fprintf(hist_fp, "%s,%s,%lu,%u,%s,%d,%lu,%lu,%lu,%lu,%lu,%lu\n",
632 		state.linename ? state.linename : "",
633 		state.node.addr.zone ? ftn_addrstr(abuf, state.node.addr) : "",
634 		(unsigned long) state.start_time,
635 		(unsigned int)  time_elapsed(state.start_time),
636 		session_status,
637 		rc,
638 		(unsigned long) send->netmail_size,
639 		(unsigned long) send->arcmail_size,
640 		(unsigned long) (send->files_size + send->freqed_size),
641 		(unsigned long) recv->netmail_size,
642 		(unsigned long) recv->arcmail_size,
643 		(unsigned long) (recv->files_size + recv->freqed_size));
644 
645 
646 	(void)file_close(hist_fp);
647 }
648 
649 /* ------------------------------------------------------------------------- */
650 /* Start session with another FTN mailer                                     */
651 /* ------------------------------------------------------------------------- */
session(void)652 int session(void)
653 {
654 	s_protinfo pi;
655 	int rc = BFERR_NOERROR;
656 	s_traffic traff_send;
657 	s_traffic traff_recv;
658 	char *p;
659 
660 	memset(&traff_send, '\0', sizeof(s_traffic));
661 	memset(&traff_recv, '\0', sizeof(s_traffic));
662 
663 	/* Store session start time */
664 	state.start_time = time(NULL);
665 
666 	if( state.session == SESSION_UNKNOWN )
667 	{
668 		rc = state.caller ? session_init_outgoing()
669 		                  : session_init_incoming();
670 
671 		if( rc )
672 			gotoexit(BFERR_HANDSHAKE_ERROR);
673 	}
674 
675 	/* -------------------------------------------------------------- */
676 	/* Handshake part                                                 */
677 	/* -------------------------------------------------------------- */
678 	switch( state.session ) {
679 	case SESSION_EMSI:
680 		state.handshake = &handshake_protocol_emsi;
681 		break;
682 	case SESSION_BINKP:
683 		state.handshake = &handshake_protocol_binkp;
684 		break;
685 	case SESSION_YOOHOO:
686 		state.handshake = &handshake_protocol_yoohoo;
687 		break;
688 	case SESSION_FTSC:
689 		bf_log("%sbound FTS-1 session", state.caller?"out":"in");
690 		bf_log("FTS-1 session not availabe");
691 		gotoexit(BFERR_HANDSHAKE_ERROR);
692 	case SESSION_UNKNOWN:
693 		ASSERT_MSG();
694 		gotoexit(BFERR_HANDSHAKE_ERROR);
695 	default:
696 		ASSERT_MSG();
697 		gotoexit(BFERR_HANDSHAKE_ERROR);
698 	}
699 
700 	state.handshake->init(state.handshake);
701 
702 	bf_log("%sbound %s session",
703 		state.caller ? "out" : "in", state.handshake->verbal_name);
704 
705 	rc = state.caller ? state.handshake->outgoing_session(state.handshake)
706 	                  : state.handshake->incoming_session(state.handshake);
707 
708 	DEB((D_PROT, "session: handshake rc = %d", rc));
709 
710 	if( rc != HRC_OK )
711 	{
712 		const char *errmsg = NULL;
713 
714 		switch(rc) {
715 		case HRC_LOW_SPEED:
716 			errmsg = "connect speed too low";
717 			rc = BFERR_CONNECT_TOOLOW;
718 			break;
719 		case HRC_BAD_PASSWD:
720 			errmsg = "security violation";
721 			rc = BFERR_HANDSHAKE_ERROR;
722 			break;
723 		case HRC_NO_ADDRESS:
724 			errmsg = "no expected address was presented";
725 			rc = BFERR_HANDSHAKE_ERROR;
726 			break;
727 		case HRC_NO_PROTOS:
728 			errmsg = "no common protocols";
729 			rc = BFERR_HANDSHAKE_ERROR;
730 			break;
731 		case HRC_BUSY:
732 			errmsg = "all remote addresses are busy";
733 			rc = BFERR_HANDSHAKE_ERROR;
734 			break;
735 		case HRC_FATAL_ERR:
736 		case HRC_TEMP_ERR:
737 		case HRC_OTHER_ERR:
738 			errmsg = NULL;
739 			rc = BFERR_HANDSHAKE_ERROR;
740 			break;
741 		default:
742 			errmsg = "unexpected error number";
743 			rc = BFERR_HANDSHAKE_ERROR;
744 			break;
745 		}
746 
747 		if( errmsg )
748 			bf_log("abort session due to: %s", errmsg);
749 	}
750 	else
751 	{
752 		/*
753 		 * Execute 'run_after_handshake' command
754 		 */
755 		if( (p = conf_string(cf_run_after_handshake)) )
756 			session_run_command(p);
757 
758 		/*
759 		 * Files transfer part
760 		 */
761 		DEB((D_FREQ, "setreqstat: Our FREQ processor status: \"%s\"",
762 				( state.reqstat == REQS_ALLOW    ) ? "Allowed":
763 				( state.reqstat == REQS_NOTALLOW ) ? "Not allowed now":
764 				( state.reqstat == REQS_DISABLED ) ? "No FREQs available":"Error"));
765 		DEB((D_HSHAKE, "session: decided to use %s protocol",
766 				Protocols[state.handshake->protocol]));
767 
768 		/*
769 		 * Log expected traffic
770 		 */
771 		session_traffic();
772 
773 		init_protinfo(&pi, state.caller);
774 
775 		switch(state.handshake->protocol) {
776 		case PROT_BINKP:
777 			rc = binkp_transfer(&pi);
778 			break;
779 		case PROT_ZMODEM:
780 		case PROT_ZEDZAP:
781 		case PROT_DIRZAP:
782 			rc = state.caller ? tx_zmodem(&pi, state.caller)
783 			                  : rx_zmodem(&pi, state.caller);
784 			if( rc == PRC_NOERROR )
785 			{
786 				rc = state.caller ? rx_zmodem(&pi, state.caller)
787 				                  : tx_zmodem(&pi, state.caller);
788 			}
789 			break;
790 		case PROT_JANUS:
791 			bf_log("Janus is not available in current version");
792 			break;
793 		case PROT_HYDRA:
794 			rc = hydra(&pi, state.sopts.hydraRH1);
795 			break;
796 		case PROT_NOPROT:
797 			bf_log("no common protocols available");
798 			break;
799 		default:
800 			ASSERT_MSG();
801 			break;
802 		}
803 
804 		/*
805 		 * Convert value returned by protocol to the BForce return code
806 		 */
807 		switch(rc) {
808 		case PRC_NOERROR:       rc = BFERR_NOERROR; break;
809 		case PRC_ERROR:
810 		case PRC_REMOTEABORTED:
811 		case PRC_LOCALABORTED:  rc = BFERR_XMITERROR; break;
812 		case PRC_CPSTOOLOW:     rc = BFERR_CPSTOOLOW; break;
813 		case PRC_STOPTIME:      rc = BFERR_STOPTIME; break;
814 		default:                ASSERT_MSG();
815 		}
816 		state.session_rc = rc;
817 
818 		/*
819 		 * Do session clenup (remove temp. files, etc.)
820 		 */
821 		(void)p_session_cleanup(&pi, (rc == BFERR_NOERROR));
822 
823 		if( rc == BFERR_NOERROR )
824 		{
825 			/*
826 			 * Flush our 'stdout' buffer
827 			 */
828 			FLUSHOUT();
829 
830 			/*
831 			 * Remove empty .?lo files
832 			 */
833 			(void)out_flo_unlinkempty(state.queue.flotab, state.queue.flonum);
834 
835 			/*
836 			 * Wait a little if we are answering on incoming call
837 			 * (to be sure that all data will be sent) (?)
838 			 */
839 			if( !state.caller ) sleep(1);
840 		}
841 
842 		/*
843 		 * Remove all .bsy locks
844 		 */
845 		out_bsy_unlockall();
846 
847 		/*
848 		 * Write total amount of received/sent bytes, files, etc.
849 		 */
850 		p_log_txrxstat(&pi);
851 
852 		/*
853 		 * Save session traffic before deiniting
854 		 */
855 		traff_send = pi.traffic_sent;
856 		traff_recv = pi.traffic_rcvd;
857 
858 		deinit_protinfo(&pi);
859 
860 		/*
861 		 * Execute 'run_after_session' command
862 		 */
863 		if( (p = conf_string(cf_run_after_session)) )
864 			session_run_command(p);
865 	}
866 
867 exit:
868 	state.session_rc = rc;
869 	session_update_history(&traff_send, &traff_recv, rc);
870 
871 	return rc;
872 }
873