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

rlogin.c 5.05 KB
Newer Older
deuce's avatar
deuce committed
1 2
/* Copyright (C), 2007 by Stephen Hurd */

3
/* $Id: rlogin.c,v 1.38 2020/06/27 00:04:50 deuce Exp $ */
4 5 6 7 8 9 10 11 12

#include <stdlib.h>

#include "sockwrap.h"

#include "bbslist.h"
#include "conn.h"
#include "uifcinit.h"

13
SOCKET rlogin_sock=INVALID_SOCKET;
14

15 16 17
#ifdef __BORLANDC__
#pragma argsused
#endif
18 19 20
void rlogin_input_thread(void *args)
{
	int		rd;
21
	int	buffered;
22 23
	size_t	buffer;

deuce's avatar
deuce committed
24
	SetThreadName("RLogin Input");
25
	conn_api.input_thread_running=1;
26
	while(rlogin_sock != INVALID_SOCKET && !conn_api.terminate) {
27
		if (socket_readable(rlogin_sock, -1)) {
28
			rd=recv(rlogin_sock, conn_api.rd_buf, conn_api.rd_buf_size, 0);
29 30 31 32 33 34
			if(rd <= 0)
				break;
		}
		buffered=0;
		while(buffered < rd) {
			pthread_mutex_lock(&(conn_inbuf.mutex));
35
			buffer=conn_buf_wait_free(&conn_inbuf, rd-buffered, 1000);
36 37 38 39
			buffered+=conn_buf_put(&conn_inbuf, conn_api.rd_buf+buffered, buffer);
			pthread_mutex_unlock(&(conn_inbuf.mutex));
		}
	}
40
	conn_api.input_thread_running=2;
41 42
}

43 44 45
#ifdef __BORLANDC__
#pragma argsused
#endif
46 47 48 49
void rlogin_output_thread(void *args)
{
	int		wr;
	int		ret;
50
	int	sent;
51

deuce's avatar
deuce committed
52
	SetThreadName("RLogin Output");
53
	conn_api.output_thread_running=1;
54
	while(rlogin_sock != INVALID_SOCKET && !conn_api.terminate) {
55
		pthread_mutex_lock(&(conn_outbuf.mutex));
56
		ret=0;
57 58 59 60 61 62
		wr=conn_buf_wait_bytes(&conn_outbuf, 1, 100);
		if(wr) {
			wr=conn_buf_get(&conn_outbuf, conn_api.wr_buf, conn_api.wr_buf_size);
			pthread_mutex_unlock(&(conn_outbuf.mutex));
			sent=0;
			while(sent < wr) {
63
				if (socket_writable(rlogin_sock, -1)) {
64
					ret=sendsocket(rlogin_sock, conn_api.wr_buf+sent, wr-sent);
65 66 67 68 69 70 71 72 73 74 75
					if(ret==-1)
						break;
					sent+=ret;
				}
			}
		}
		else
			pthread_mutex_unlock(&(conn_outbuf.mutex));
		if(ret==-1)
			break;
	}
76
	conn_api.output_thread_running=2;
77 78 79 80 81 82 83
}

int rlogin_connect(struct bbslist *bbs)
{
	char	*ruser;
	char	*passwd;

84 85
	if (!bbs->hidepopups)
		init_uifc(TRUE, TRUE);
86 87 88

	ruser=bbs->user;
	passwd=bbs->password;
89
	if(bbs->conn_type==CONN_TYPE_RLOGIN_REVERSED) {
90 91 92 93
		passwd=bbs->user;
		ruser=bbs->password;
	}

94 95
	rlogin_sock=conn_socket_connect(bbs);
	if(rlogin_sock==INVALID_SOCKET)
96 97
		return(-1);

98 99 100 101 102 103 104 105 106 107 108
	if(!create_conn_buf(&conn_inbuf, BUFFER_SIZE))
		return(-1);
	if(!create_conn_buf(&conn_outbuf, BUFFER_SIZE)) {
		destroy_conn_buf(&conn_inbuf);
		return(-1);
	}
	if(!(conn_api.rd_buf=(unsigned char *)malloc(BUFFER_SIZE))) {
		destroy_conn_buf(&conn_inbuf);
		destroy_conn_buf(&conn_outbuf);
		return(-1);
	}
109
	conn_api.rd_buf_size=BUFFER_SIZE;
110
	if(!(conn_api.wr_buf=(unsigned char *)malloc(BUFFER_SIZE))) {
deuce's avatar
deuce committed
111
		FREE_AND_NULL(conn_api.rd_buf);
112 113 114 115
		destroy_conn_buf(&conn_inbuf);
		destroy_conn_buf(&conn_outbuf);
		return(-1);
	}
116 117
	conn_api.wr_buf_size=BUFFER_SIZE;

118
	if(bbs->conn_type == CONN_TYPE_RLOGIN || bbs->conn_type == CONN_TYPE_RLOGIN_REVERSED) {
119 120 121 122 123
		conn_send("",1,1000);
		conn_send(passwd,strlen(passwd)+1,1000);
		conn_send(ruser,strlen(ruser)+1,1000);
		if(bbs->bpsrate) {
			char	sbuf[30];
124 125 126 127 128 129 130
			sprintf(sbuf, "%s/%d", get_emulation_str(get_emulation(bbs)), bbs->bpsrate);

			conn_send(sbuf, strlen(sbuf)+1,1000);
		}
		else {
			char	sbuf[30];
			sprintf(sbuf, "%s/115200", get_emulation_str(get_emulation(bbs)));
131 132 133 134 135

			conn_send(sbuf, strlen(sbuf)+1,1000);
		}
	}

136 137 138 139 140 141 142
	/* Negotiate with GHost and bail if there's apparently no GHost listening. */
	if(bbs->conn_type == CONN_TYPE_MBBS_GHOST) {
		char	sbuf[80];
		char	rbuf[10];
		int		idx, ret;

		/* Check to make sure GHost is actually listening */
143
		sendsocket(rlogin_sock, "\r\nMBBS: PING\r\n", 14);
144 145

		idx = 0;
146 147 148 149
		while (socket_readable(rlogin_sock, 1000)) {
			ret = recv(rlogin_sock, rbuf+idx, 1, 0);
			if (ret == -1)
				break;
150 151 152
			rbuf[++idx] = 0;

			/* It says ERROR, but this is a good response to PING. */
153
			if (strstr(rbuf,"ERROR\r\n")) {
154 155 156 157 158 159 160 161 162 163 164 165 166 167
				break;
			}

			/* We didn't receive the desired response in time, so bail. */
			if (idx >= sizeof(rbuf)) {
				return(-1);
			}
		}

		if (ret < 1) {
			return(-1);
		}

		sprintf(sbuf, "MBBS: %s %d '%s' %d %s\r\n",
168
			(bbs->ghost_program[0]) ? bbs->ghost_program : bbs->password, /* Program name */
169 170 171 172 173
			2, /* GHost protocol version */
			bbs->user, /* User's full name */
			999, /* Time remaining */
			"GR" /* GR = ANSI, NG = ASCII */
		);
174
		sendsocket(rlogin_sock, sbuf, strlen(sbuf));
175 176

		idx = 0;
177 178 179 180
		while (socket_readable(rlogin_sock, 1000)) {
			ret = recv(rlogin_sock, rbuf+idx, 1, 0);
			if (ret == -1)
				break;
181 182 183
			rbuf[++idx] = 0;

			/* GHost says it's launching the program, so pass terminal to user. */
184
			if (strstr(rbuf,"OK\r\n")) {
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
				break;
			}

			/* We didn't receive the desired response in time, so bail. */
			if (idx >= sizeof(rbuf)) {
				return(-1);
			}
		}

		if (ret < 1) {
			return(-1);
		}

	}

200 201 202
	_beginthread(rlogin_output_thread, 0, NULL);
	_beginthread(rlogin_input_thread, 0, NULL);

203 204 205
	if (!bbs->hidepopups) {
		uifc.pop(NULL);
	}
206 207 208 209 210 211

	return(0);
}

int rlogin_close(void)
{
212 213
	char garbage[1024];

214
	conn_api.terminate=1;
215
	closesocket(rlogin_sock);
216
	while(conn_api.input_thread_running == 1 || conn_api.output_thread_running == 1) {
217
		conn_recv_upto(garbage, sizeof(garbage), 0);
218
		SLEEP(1);
219
	}
220 221 222 223 224 225
	destroy_conn_buf(&conn_inbuf);
	destroy_conn_buf(&conn_outbuf);
	FREE_AND_NULL(conn_api.rd_buf);
	FREE_AND_NULL(conn_api.wr_buf);
	return(0);
}