./ MultiCS.r82 / telnet.c
#include "common.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>

#ifdef WIN32

#include <windows.h>
#include <sys/types.h>
#include <sys/_default_fcntl.h>
#include <sys/poll.h>
#include <cygwin/types.h>
#include <cygwin/socket.h>
#include <sys/errno.h>
#include <cygwin/in.h>
#include <sched.h>
#include <netdb.h>
#include <netinet/tcp.h>

#else

#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#include <errno.h>
#include <pthread.h>
#include <poll.h>
#include <sys/prctl.h>

#endif

#include "debug.h"
#include "convert.h"
#include "tools.h"
#include "threads.h"
#include "ecmdata.h"

#ifdef CCCAM
#include "msg-cccam.h"
#endif

#include "config.h"
#include "sockets.h"

#include "telnet.h"
#include "main.h"
#include "parser.h"
#include "httpserver.h"

int writes( int fd, char *str )
{
	return write(fd, str, strlen(str) );
}

char *getcountrycodebyip(uint32_t ip);

void *telnetprocess(int *param )
{
	int fd = *param;
	free(param);

	char buf[4096];
	char str[256];
	char wbuf[4096];
	int len;
	//
	writes(fd, "Welcome to Telnet Server\r\n\r\nLogin: ");

	len = recv( fd, buf, sizeof(buf), MSG_NOSIGNAL);
	if (len<=0) { close(fd); return NULL; }
	//printf(" Received(%d): '%s'\r\n", len, buf);
	if ( (buf[len-2]!='\r')||(buf[len-1]!='\n') )  { close(fd); return NULL; }
	buf[len-2] = 0;
	if ( strcmp(buf, cfg.telnet.user) ) { 
		writes(fd, "wrong username, bye.\r\n");
		close(fd);
		return NULL;
	}
	//
	writes(fd, "Password: ");
	len = recv( fd, buf, sizeof(buf), MSG_NOSIGNAL);
	if (len<=0) { close(fd); return NULL; }
	//printf(" Received(%d): '%s'\r\n", len, buf);
	if ( (buf[len-2]!='\r')||(buf[len-1]!='\n') )  { close(fd); return NULL; }
	buf[len-2] = 0;
	if ( strcmp(buf, cfg.telnet.pass) ) {
		writes(fd, "wrong password, bye.\r\n");
		close(fd);
		return NULL;
	}
	strcpy(buf, "\r\n\r\ntype 'help' for command list\r\n");write(fd, buf, strlen(buf) );

	while ( 1 ) {
		writes(fd, "\r\n[command]: ");
		len = recv( fd, buf, sizeof(buf), MSG_NOSIGNAL);
		if (len<=0) { close(fd); return NULL; }
		//printf(" Received(%d): %s", len, buf);
		if ( (buf[len-2]!='\r')||(buf[len-1]!='\n') )  { close(fd); return NULL; }
		buf[len-2] = 0;

		iparser = buf;
		parse_spaces();
		if (*iparser==0) continue;
		if (!parse_name(str)) continue;
		uppercase(str);

		if ( !strcmp(str, "EXIT") || !strcmp(str, "QUIT") ) {
			writes(fd, "bye.\r\n");
			break;
		}
		else if ( !strcmp(str, "UPTIME") ) {
			unsigned int d= GetTickCount()/1000;
			sprintf( wbuf,"Uptime: %02dd %02d:%02d:%02d\r\n", d/(3600*24), (d/3600)%24, (d/60)%60, d%60);
			writes(fd, wbuf);
		}
		else if ( !strcmp(str, "STAT") ) {
			sprintf( wbuf,"Total Profiles: %d\r\nTotal Servers: %d\r\nTotal Cache Servers: %d\r\nTotal CCcam Servers: %d\r\n", cfg.totalprofiles, cfg.totalservers, cfg.cache.totalservers, cfg.cccam.totalservers);
			writes(fd, wbuf);
		}
		else if ( !strcmp(str, "DEBUG") ) {
			int i=idbgline;
			do {
				sprintf( wbuf, "%s", dbgline[i] );
				writes(fd, wbuf);
				i++;
				if (i>=MAX_DBGLINES) i=0;
			} while (i!=idbgline);
		}
		else if ( !strcmp(str, "LOADAVG") ) {
			FILE *fp = fopen ("/proc/loadavg", "r");
			if ( fgets(wbuf, sizeof(wbuf), fp) ) writes(fd, wbuf);
			fclose(fp);
		}
		else if ( !strcmp(str, "MEMINFO") ) {
			FILE *fp = fopen ("/proc/meminfo", "r");
			if ( fgets(wbuf, sizeof(wbuf), fp) ) writes(fd, wbuf);
			if ( fgets(wbuf, sizeof(wbuf), fp) ) writes(fd, wbuf);
			fclose(fp);
		}
		else if ( !strcmp(str, "CPUINFO") ) {
			FILE *fp = fopen ("/proc/cpuinfo", "r");
			while ( fgets(wbuf, sizeof(wbuf), fp) ) writes(fd, wbuf);
			fclose(fp);
		}
		else if ( !strcmp(str, "SCHED") ) {
			if (parse_name(str)) {
				uppercase(str);
				if ( !strcmp(str, "CCCAM") ) {
					sprintf( str, "/proc/%d/sched", prg.pid_cc_msg);
					FILE *fp = fopen ( str, "r");
					while ( fgets(wbuf, sizeof(wbuf), fp) ) writes(fd, wbuf);
					fclose(fp);
				}
				else if ( !strcmp(str, "NEWCAMD") ) {
					sprintf( str, "/proc/%d/sched", prg.pid_cs_msg);
					FILE *fp = fopen ( str, "r");
					while ( fgets(wbuf, sizeof(wbuf), fp) ) writes(fd, wbuf);
					fclose(fp);
				}
				else if ( !strcmp(str, "ECM") ) {
					sprintf( str, "/proc/%d/sched", prg.pid_msg);
					FILE *fp = fopen ( str, "r");
					while ( fgets(wbuf, sizeof(wbuf), fp) ) writes(fd, wbuf);
					fclose(fp);
				}
				else if ( !strcmp(str, "MGCAMD") ) {
					sprintf( str, "/proc/%d/sched", prg.pid_mg_msg);
					FILE *fp = fopen ( str, "r");
					while ( fgets(wbuf, sizeof(wbuf), fp) ) writes(fd, wbuf);
					fclose(fp);
				}
#ifdef CACHEEX
				else if ( !strcmp(str, "CACHEEX") ) {
					sprintf( str, "/proc/%d/sched", prg.pid_ccex_msg);
					FILE *fp = fopen ( str, "r");
					while ( fgets(wbuf, sizeof(wbuf), fp) ) writes(fd, wbuf);
					fclose(fp);
				}
#endif
				else if ( !strcmp(str, "CACHE") ) {
					sprintf( str, "/proc/%d/sched", prg.pid_cache);
					FILE *fp = fopen ( str, "r");
					while ( fgets(wbuf, sizeof(wbuf), fp) ) writes(fd, wbuf);
					fclose(fp);
				}
			}
			else {
				sprintf( str, "/proc/%d/sched", prg.pid_main);
				FILE *fp = fopen ( str, "r");
				while ( fgets(wbuf, sizeof(wbuf), fp) ) writes(fd, wbuf);
				fclose(fp);
			}
		}
		else if ( !strcmp(str, "HELP") ) {
			writes(fd, " Commands: help - uptime - stat - cccam - mgcamd - debug - loadavg - cpuinfo - meminfo - exit/quit\r\n");
		}
		else if (!strcmp(str,"CCCAM")) {
			if (!parse_int(str)) {
				int index = 0;
				struct cccam_server_data *srv = cfg.cccam.server;
				while (srv) {
					index++;
					sprintf( wbuf, "id:%d  Port:%d", srv->id, srv->port);
					if (srv->handle>0) strcat( wbuf, " Status:ON "); else strcat( wbuf, " Status:OFF");
					int total, connected, active;
					cccam_clients( srv, &total, &connected, &active );
					sprintf( str, "Clients Total:%d, Connected:%d, Active:%d", total, connected, active );
					strcat( wbuf, str );
					strcat( wbuf, "\r\n");
					writes(fd, wbuf);
					srv = srv->next;
				}
				sprintf(wbuf, "Total CCcam servers = %d\r\n", index);
				writes(fd, wbuf);
			}
			else { // cccam <cientname>
				struct cccam_server_data *cccam = getcccamserverbyid( atoi(str) );
				if (!cccam) continue;
				if (!parse_name(str)) continue;
				struct cc_client_data *cli = getcccamclientbyname( cccam, str );
				if (!cli) continue;
				if (cli->connection.status>0) {
					char *p = getcountrycodebyip(cli->ip);
					if (p) 
						sprintf(wbuf, "<tr><td>%s</td><td>%s</td><td class=online>Connected</td><td>[%s] %s</td>", cfg.http.title, cli->user, p, ip2string(cli->ip) );
					else
						sprintf(wbuf, "<tr><td>%s</td><td>%s</td><td class=online>Connected</td><td>%s</td>", cfg.http.title, cli->user, ip2string(cli->ip) );
					//Last Used Share
					if ( cli->lastecm.caid ) {
						char tmp[512];
						if (cli->lastecm.status)
							sprintf( tmp,"<td class=success>channel %s (%dms) OK</td>", getchname(cli->lastecm.caid, cli->lastecm.prov, cli->lastecm.sid) , cli->lastecm.decodetime );
						else
							sprintf( tmp,"<td class=failed>channel %s (%dms) NOK</td>", getchname(cli->lastecm.caid, cli->lastecm.prov, cli->lastecm.sid) , cli->lastecm.decodetime );
						strcat( wbuf, tmp);
						// last time
						unsigned int d= (GetTickCount()-cli->ecm.recvtime)/1000;
						sprintf( tmp,"<td>%02dd %02d:%02d:%02d</td></tr>\r\n", d/(3600*24), (d/3600)%24, (d/60)%60, d%60);
						strcat( wbuf, tmp);
					} else strcat( wbuf, "<td> </td><td> </td></tr>\r\n");
				}
				else {
					if (cli->connection.lastseen) {
						uint32_t d = (GetTickCount()-cli->connection.lastseen)/1000;
						sprintf( wbuf,"<tr><td>%s</td><td>%s</td><td class=offline>Disconnected</td><td>Last Seen</td><td>%02dd %02d:%02d:%02d</td></tr>\r\n", cfg.http.title, cli->user, d/(3600*24),(d/3600)%24,(d/60)%60,d%60);
					}
					else sprintf(wbuf, "<tr><td>%s</td><td>%s</td><td class=offline>Disconnected</td><td> </td><td> </td></tr>\r\n", cfg.http.title, cli->user );
				}
				writes(fd, wbuf);
			}
		}
		else if (!strcmp(str,"MGCAMD")) {
			if (!parse_int(str)) {
				int index = 0;
				struct mgcamdserver_data *srv = cfg.mgcamd.server;
				while (srv) {
					index++;
					sprintf( wbuf, "id:%d  Port:%d", srv->id, srv->port);
					if (srv->handle>0) strcat( wbuf, " Status:ON "); else strcat( wbuf, " Status:OFF");
					int total, connected, active;
					mgcamd_clients( srv, &total, &connected, &active );
					sprintf( str, "Clients Total:%d, Connected:%d, Active:%d", total, connected, active );
					strcat( wbuf, str );
					strcat( wbuf, "\r\n");
					writes(fd, wbuf);
					srv = srv->next;
				}
				sprintf(wbuf, "Total Mgcamd servers = %d\r\n", index);
				writes(fd, wbuf);
			}
			else { // mgcamd <cientname>
				struct mgcamdserver_data *srv = getmgcamdserverbyid( atoi(str) );
				if (!srv) continue;
				if (!parse_name(str)) continue;
				struct mg_client_data *cli = getmgcamdclientbyname( srv, str );
				if (!cli) continue;
				if (cli->handle>0) {
					char *p = getcountrycodebyip(cli->ip);
					if (p) 
						sprintf(wbuf, "<tr><td>%s</td><td>%s</td><td class=online>Connected</td><td>[%s] %s</td>", cfg.http.title, cli->user, p, ip2string(cli->ip) );
					else
						sprintf(wbuf, "<tr><td>%s</td><td>%s</td><td class=online>Connected</td><td>%s</td>", cfg.http.title, cli->user, ip2string(cli->ip) );
					//Last Used Share
					if ( cli->lastecm.caid ) {
						char tmp[512];
						if (cli->lastecm.status)
							sprintf( tmp,"<td class=success>channel %s (%dms) OK</td>", getchname(cli->lastecm.caid, cli->lastecm.prov, cli->lastecm.sid) , cli->lastecm.decodetime );
						else
							sprintf( tmp,"<td class=failed>channel %s (%dms) NOK</td>", getchname(cli->lastecm.caid, cli->lastecm.prov, cli->lastecm.sid) , cli->lastecm.decodetime );
						strcat( wbuf, tmp);
						// last time
						unsigned int d= (GetTickCount()-cli->ecm.recvtime)/1000;
						sprintf( tmp,"<td>%02dd %02d:%02d:%02d</td></tr>\r\n", d/(3600*24), (d/3600)%24, (d/60)%60, d%60);
						strcat( wbuf, tmp);
					} else strcat( wbuf, "<td> </td><td> </td></tr>\r\n");
				}
				else sprintf(wbuf, "<tr><td>%s</td><td>%s</td><td class=offline>Disconnected</td><td> </td><td> </td></tr>\r\n", cfg.http.title, cli->user );
				writes(fd, wbuf);
			}
		}
		else if (!strcmp(str,"UPDATE")) {
			if (parse_name(str)) {
				uppercase(str);
				if ( !strcmp(str, "CCCAM") ) {
					if (parse_int(str)) {
						struct cccam_server_data *cccam = getcccamserverbyid( atoi(str) );
						if (!cccam) continue;
						// user
						if (!parse_str(str)) continue;
						struct cc_client_data *cli = getcccamclientbyname( cccam, str );
						if (!cli) continue;
						// pass
						if (!parse_str(str)) continue;
						if ( strcmp(str, "*") ) {
							if ( strcmp(cli->pass, str) ) {
								strcpy(cli->pass, str);
								// disconnect
								if (cli->connection.status>0) cc_disconnect_cli(cli);
							}
						}
						// date
						if (!parse_str(str)) continue;
						if ( strcmp(str, "*") ) {
							if ( (str[4]=='-')&&(str[7]=='-') ) strptime(  str, "%Y-%m-%d %H", &cli->enddate);
							else if ( (str[2]=='-')&&(str[5]=='-') ) strptime(  str, "%d-%m-%Y %H", &cli->enddate);
						}
						//
						if (parse_int(str)) {
							if (str[0]=='1') cli->flags &= ~FLAG_DISABLE; 
							else {
								cli->flags |= FLAG_DISABLE;
								if (cli->connection.status>0) cc_disconnect_cli(cli);
							}
						}
						sprintf(wbuf, "CCcam Client '%s' Updated\r\n", cli->user);
						writes(fd, wbuf);
					} else writes(fd, "update cccam <server id> <client name> <password> <expire-date> <1:enable/0:disable>\r\n");
				}
				else
				if ( !strcmp(str, "MGCAMD") ) {
					if (parse_int(str)) {
						struct mgcamdserver_data *mgcamd = getmgcamdserverbyid( atoi(str) );
						if (!mgcamd) continue;
						// user
						if (!parse_str(str)) continue;
						struct mg_client_data *cli = getmgcamdclientbyname( mgcamd, str );
						if (!cli) continue;
						// pass
						if (!parse_str(str)) continue;
						if ( strcmp(str, "*") ) {
							if ( strcmp(cli->pass, str) ) {
								strcpy(cli->pass, str);
								// disconnect
								if (cli->connection.status>0) mg_disconnect_cli(cli);
							}
						}
						// date
						if (!parse_name(str)) continue;
						if ( strcmp(str, "*") ) {
							if ( (str[4]=='-')&&(str[7]=='-') ) strptime(  str, "%Y-%m-%d %H", &cli->enddate);
							else if ( (str[2]=='-')&&(str[5]=='-') ) strptime(  str, "%d-%m-%Y %H", &cli->enddate);
						}
						//
						if (parse_int(str)) {
							if (str[0]=='1') cli->flags &= ~FLAG_DISABLE;
							else {
								cli->flags |= FLAG_DISABLE;
								if (cli->connection.status>0) mg_disconnect_cli(cli);
							}
						}
						sprintf(wbuf, "mgcamd Client '%s' Updated\r\n", cli->user);
						writes(fd, wbuf);
					} else writes(fd, "update mgcamd <server id> <client name> <password> <expire-date> <1:enable/0:disable>\r\n");
				}

			}
		}
		else {
			writes(fd, "unknown command.\r\n");
		}

	}

	close(fd);
	return NULL;
}




void *telnet_thread(void *param)
{
	int clientsock;
	struct sockaddr_in client_addr;
	socklen_t socklen = sizeof(client_addr);
	prctl(PR_SET_NAME,"Telnet",0,0,0);
	while(1) {
		if (cfg.telnet.handle>0) {
			struct pollfd pfd;
			pfd.fd = cfg.telnet.handle;
			pfd.events = POLLIN | POLLPRI;
			int retval = poll(&pfd, 1, 3002);
			if ( retval>0 ) {
				if ( pfd.revents & (POLLIN|POLLPRI) ) {
					clientsock = accept(cfg.telnet.handle, (struct sockaddr*)&client_addr, /*(socklen_t*)*/&socklen);
					if ( clientsock<0 ) {
						debugf(getdbgflag(DBG_HTTP,0,0)," telnet Server: Accept Error\n");
						break;
					}
					else {
						//SetSocketNoDelay(clientsock);
						pthread_t cli_tid;
						int *param = malloc( sizeof(int) );
						*param = clientsock;
						if ( !create_thread(&cli_tid, (threadfn)telnetprocess,param) ) {
							free( param );
							close( clientsock );
						}
					}
				}
			}
			else if (retval<0) {
				debugf(getdbgflag(DBG_HTTP,0,0)," THREAD telnet: poll error %d(errno=%d)\n", retval, errno);
				usleep(50000);
			}
		} else usleep(100000);
	}// While

	debugf(getdbgflag(DBG_HTTP,0,0),"Exiting telnet Thread\n");
	return NULL;
}

pthread_t telnet_tid;
int start_thread_telnet()
{
	create_thread(&telnet_tid, telnet_thread, NULL); // Priority
	return 0;
}