1 //
2 // anyRemote
3 // a wi-fi or bluetooth remote for your PC.
4 //
5 // Copyright (C) 2006-2016 Mikhail Fedotov <anyremote@mail.ru>
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21
22 #include <errno.h>
23 #include <pwd.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28
29 #include "common.h"
30 #include "lib_wrapper.h"
31 #include "utils.h"
32 #include "conf.h"
33 #include "mode.h"
34 #include "var.h"
35 #include "alarm.h"
36 #include "queue.h"
37 #include "mutex.h"
38 #include "timer.h"
39
40 extern char tmp[MAXMAXLEN];
41 extern CONF conf;
42
43 // Some globals
44
45 char logfile [MAXLEN];
46
47 // used by Flush() command to temporary store old configuration
48 static mode *flushModes = NULL;
49 static SingleList *flushAlarms = NULL;
50 static HashTable *flushTimers = NULL;
51
52 #ifdef USE_ICONV
53
54 #include <iconv.h>
55
56 iconv_t convertorTo = (iconv_t) -1;
57 iconv_t convertorFrom = (iconv_t) -1;
58
59 #endif
60
61 //////////////////////////////////////////////////////////////////////////////////
62 //
63 // Functions related to logging
64 //
65 //////////////////////////////////////////////////////////////////////////////////
66
initFile(char * what,const char * name)67 static void initFile(char* what, const char* name)
68 {
69 // store data in first arg
70
71 int useuser = 0;
72
73 char *prefix = dupVarValue("TmpDir");
74 char *h = getenv("HOME");
75
76 if (prefix) {
77 strcat(what, prefix);
78 if (h) {
79 if (strncmp(prefix, h, strlen(h)) != 0) {
80 useuser = 1;
81 }
82 } else {
83 useuser = 1;
84 }
85 } else {
86 if (h) {
87 strcat(what, h);
88 strcat(what, "/.anyRemote");
89 } else { // could it ever happen ?
90 strcat(what, "/tmp");
91 useuser = 1;
92 }
93 }
94 strcat(what, name);
95
96 if (useuser == 1) {
97 char *u = getenv("USER");
98 if (prefix && u) {
99 strcat(what, ".");
100 strcat(what, u);
101 }
102 }
103
104 free(prefix);
105 return;
106 }
107
initLog()108 void initLog()
109 {
110 if (getLog()) {
111
112 initFile(logfile, LOGFILE);
113
114 printf("INFO: log file is %s\n",logfile);
115
116 // Just truncate file
117 FILE *fplog = fopen(logfile, "w");
118 if (fplog) {
119 fclose(fplog);
120 }
121 if(getuid()==0 && conf.uid) { // do not open file as superuser
122 #ifdef __cplusplus
123 int dummy =
124 #endif
125 chown(logfile,conf.uid,conf.gid);
126 }
127
128 mutexNew(M_LOG);
129
130 printTime();
131 sprintf(tmp, "anyRemote v%s", PACKAGE_VERSION);
132 logger(L_CFG, tmp);
133 }
134 }
135
releaseLog()136 void releaseLog()
137 {
138 mutexRemove(M_LOG);
139 }
140
logger2(const char * head,const char * str)141 static void logger2(const char *head, const char *str)
142 {
143 //printf("logger ENTER\n");fflush(stdout);
144 FILE *fplog;
145 time_t logtime;
146
147 //struct timeval tv;
148 //struct timezone tz;
149
150 if (!getLog() ||
151 logfile[0] == '\0' ||
152 (head && strcmp(head, "DBG") == 0 && getDebug() == 0)) {
153 return;
154 }
155
156 mutexLock(M_LOG);
157
158 fplog = fopen(logfile, "a");
159 if (fplog!=NULL) {
160 if (head && strcmp(head, "CFG") != 0) {
161
162 time(&logtime);
163 struct tm* timeinfo = localtime (&logtime );
164
165 //gettimeofday(&tv, &tz);
166
167 char stime[32];
168 stime[8] = '\0';
169
170 sprintf(stime, "%2d:%2d:%2d", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
171 //sprintf(stime, "%2d:%2d", tv.tv_sec, tv.tv_usec/1000);
172
173 fprintf(fplog, "[%s] - ",stime);
174 }
175 if(head != NULL && strcmp(head, "CFG") != 0) {
176 fprintf(fplog, "%s - ",head);
177 }
178 fprintf(fplog, "%s\n",str);
179
180 fclose(fplog);
181 } else {
182 printf("Can not open log file >%s<\n", logfile);
183 logfile[0] = '\0'; // print this error only once
184 }
185
186 mutexUnlock(M_LOG);
187
188 //printf("logger EXIT\n");fflush(stdout);
189 }
190
logger(int head,const char * str)191 void logger(int head, const char *str)
192 {
193 switch (head) {
194 case L_CFG:
195 logger2("CFG", str);
196 break;
197 case L_INF:
198 logger2("INF", str);
199 break;
200 case L_WARN:
201 logger2("WARNING", str);
202 break;
203 case L_ERR:
204 logger2("ERR", str);
205 break;
206 //case L_DBG:
207 default:
208 logger2("DBG", str);
209 break;
210 }
211 }
212
printTime()213 void printTime()
214 {
215 time_t logtime;
216 time(&logtime);
217
218 char *timestr = (char *) ctime(&logtime);
219 timestr[strlen(timestr)-1]=0;
220 logger(L_CFG, timestr);
221 }
222
223 //////////////////////////////////////////////////////////////////////////////////
224 //
225 // Functions related to encoding conversion
226 //
227 //////////////////////////////////////////////////////////////////////////////////
needConvert()228 int needConvert()
229 {
230 int ret = 0;
231 #ifdef USE_ICONV
232 if (convertorTo != (iconv_t) -1) {
233 ret = 1;
234 }
235 #endif
236 return ret;
237 }
238
239 #ifdef USE_ICONV
closeConvertor(void)240 void closeConvertor(void)
241 {
242 if (convertorTo != (iconv_t) -1) {
243 iconv_close(convertorTo);
244 convertorTo = (iconv_t) -1;
245 }
246 if (convertorFrom != (iconv_t) -1) {
247 iconv_close(convertorFrom);
248 convertorFrom = (iconv_t) -1;
249 }
250 }
251
encodingHook()252 void encodingHook()
253 {
254 closeConvertor();
255
256 char* to = dupVarValue("ToEncoding");
257 if (!to) return;
258
259 char* from = dupVarValue("FromEncoding");
260 if (!from) {
261 free(to);
262 return;
263 }
264
265 DEBUG2("encodingHook() start conversion from >%s< to >%s<", from, to);
266
267 convertorTo = iconv_open(to, from);
268 if (convertorTo == (iconv_t) - 1) {
269 ERROR2("Can start conversion %s -> %s, not supported by iconv()", from, to);
270 }
271
272 convertorFrom = iconv_open(from, to);
273 if (convertorFrom == (iconv_t) - 1) {
274 ERROR2("Can start conversion %s -> %s, not supported by iconv()", to, from);
275 }
276
277 free(to);
278 free(from);
279 }
280 #endif
281
282
283 //////////////////////////////////////////////////////////////////////////////////
284 //
285 // Functions related to Flush() command
286 //
287 //////////////////////////////////////////////////////////////////////////////////
288
289 extern int flushConf;
290
flushData()291 int flushData()
292 {
293 //logger(L_DBG,"flushData");
294
295 flushConf = 1;
296
297 flushModes = getModes();
298 forgetModes();
299
300 flushAlarms = getAlarms();
301 forgetAlarms();
302
303 flushTimers = getTimers();
304 forgetTimers();
305
306 // Now we ready to load new cfg.
307 return EXIT_OK;
308 }
309
flushOldConf()310 void flushOldConf()
311 {
312
313 freeTimers(flushTimers);
314 flushTimers = NULL;
315
316 freeModes(flushModes);
317 flushModes = NULL;
318
319 freeAlarms(flushAlarms);
320 flushAlarms = NULL;
321 }
322
printHelp()323 void printHelp()
324 {
325 printf("Usage: anyremote [-f conf.file] [-s peer[,peer ...]] [-log] [-a] \n");
326 printf(" [-cfgdir directory] [-tmpdir directory]\n");
327 printf(" [-fe port] [-u username] [-name SDP service name] [-password]\n");
328 printf(" or: anyremote -h|-v\n\n");
329 printf(" -h|--help print this help\n");
330 printf(" -v|--version print version of anyRemote\n");
331 printf(" -f /path/to/file specify configuration file\n");
332 printf(" -s peer[,peer ...], where peer possible values are\n");
333 printf(" tcp:<port> (Server mode - TCP/IP connection)\n");
334 printf(" bluetooth:<channel 1-32> (Server mode - bluetooth connection)\n");
335 printf(" web:<port> (Server mode - Web interface)\n");
336 printf(" cmxml:<port> (Server mode - XML interface for Cisco IP phones)\n");
337 printf(" local:/dev/ircommX (Server mode - IR connection)\n");
338 printf(" rfcomm:XX:XX:XX:XX:XX:XX:CC (AT mode - bluetooth connection,\n");
339 printf(" where XX:XX:XX:XX:XX:XX is bluetooth device address,\n");
340 printf(" and CC is channel number - integer from 1 to 32)\n");
341 printf(" /dev/ttyACM# (AT mode - cable connection)\n");
342 printf(" /dev/ircomm# (AT mode - IR connection)\n");
343 printf(" ilirc:<AF_LOCAL socket file> (use with inputlircd)\n");
344 printf(" stdin\n");
345 printf(" avahi - register SDP service using Avahi\n");
346 printf(" Default peer value is bluetooth,tcp:5197,web:5080,avahi\n");
347 printf(" It is possible to specify several peers for Server mode configuration files only\n");
348 printf(" It is possible to specify only single peer of web: or cmxml: type\n");
349 printf(" -log print verbose logging information to $HOME/.anyRemote/anyremote.log\n");
350 printf(" -cfgdir override default location of directory with configuration files\n");
351 printf(" -tmpdir override default location of directory to store temporary files\n");
352 printf(" -a reconnect automatically in case of connection failure, used only in AT-mode\n");
353 printf(" -fe <port> work as backend for GUI frontend. Use specified port to connect to frontend.\n");
354 printf(" -name <SDP service name> if bluetooth or TCP/IP connection is used, allows one to specify SDP service name\n");
355 printf(" -password ask password on connect\n");
356 printf(" password should be stored in $HOME/.anyRemote/password file in a plain text\n");
357 printf(" -u|--user <username> if started from root, allows one to set effective user ID to specified user\n\n");
358
359 }
360
getUidGid(char * username,uid_t * uid,gid_t * gid)361 int getUidGid(char *username, uid_t *uid, gid_t *gid)
362 {
363 /* Set uid and gid to the preferred user (found in setuid.h). Can either be
364 * numeric or a string, found in /etc/passwd. */
365 struct passwd *pw;
366
367 if ((pw = getpwnam(username))) {
368 // Name exists
369 *uid = pw->pw_uid;
370 *gid = pw->pw_gid;
371 return EXIT_OK;
372 }
373 /* something Bad happened, so send back an error */
374 return EXIT_NOK;
375 }
376
freeMMessage(void * ptr)377 void freeMMessage(void* ptr)
378 {
379 int *mm = (int*) ptr;
380 free(mm);
381 }
382
sendToMainThread(int * m)383 static void sendToMainThread(int *m)
384 {
385 queuePush(Q_MAIN, (void*) m);
386 }
387
sendAbort()388 void sendAbort()
389 {
390 int* i = (int*) malloc(sizeof(int));
391 *i = M_ABORT;
392 sendToMainThread(i);
393 }
394
sendDisconnect()395 void sendDisconnect()
396 {
397 int* i = (int*) malloc(sizeof(int));
398 *i = M_DISCONNECT;
399 sendToMainThread(i);
400 }
401
stripCommandEnding(char * s)402 void stripCommandEnding(char *s)
403 {
404 if (s && strlen(s) >= 2) {
405 s[strlen(s)-2] = '\0'; // strip );
406 }
407 }
408
409 //////////////////////////////////////////////////////////////////////////////////
410
errnoDebug(const char * tag,int err)411 void errnoDebug(const char* tag, int err)
412 {
413
414 DEBUG2("[DS]: %s error %d (%s)", tag, err, strerror(err));
415 /*switch (err) {
416 case EPERM:
417 DEBUG2("[DS]: %s error EPERM (Operation not permitted)", tag);
418 break;
419 case ENOENT:
420 DEBUG2("[DS]: %s error ENOENT (No such file or directory)", tag);
421 break;
422 case EINTR:
423 DEBUG2("[DS]: %s error EINTR (Interrupted system call)", tag);
424 break;
425 case EIO:
426 DEBUG2("[DS]: %s error EIO (I/O error"), tag);
427 break;
428 case EBADF:
429 DEBUG2("[DS]: %s error EBADF (Bad file number)", tag);
430 break;
431 case EAGAIN:
432 DEBUG2("[DS]: %s error EAGAIN (Try again)", tag);
433 break;
434 case ENOMEM:
435 DEBUG2("[DS]: %s error ENOMEM (Out of memory)", tag);
436 break;
437 case EBUSY:
438 DEBUG2("[DS]: %s error EBUSY (Device or resource busy)", tag);
439 break;
440 case EFAULT:
441 DEBUG2("[DS]: %s error EFAULT (Bad address)", tag);
442 break;
443 case EISDIR:
444 DEBUG2("[DS]: %s error EISDIR (Is a directory)", tag);
445 break;
446 case EINVAL:
447 DEBUG2("[DS]: %s error EINVAL (Invalid argument)", tag);
448 break;
449 case EFBIG:
450 DEBUG2("[DS]: %s error EFBIG (File too large)", tag);
451 break;
452 case ENOSPC:
453 DEBUG2("[DS]: %s error ENOSPC (No space left on device)", tag);
454 break;
455 case EPIPE:
456 DEBUG2("[DS]: %s error EPIPE (Broken pipe)", tag);
457 break;
458 case EDESTADDRREQ:
459 DEBUG2("[DS]: %s error EDESTADDRREQ (Destination address required)", tag);
460 break;
461 case ECONNRESET:
462 DEBUG2("[DS]: %s error ECONNRESET (Connection reset by peer)", tag);
463 break;
464 default :
465 DEBUG2("[DS]: %s error %d", tag, err);
466 break;
467 }*/
468 }
469 //////////////////////////////////////////////////////////////////////////////////
470 //
471 // iconv() support
472 //
473 //////////////////////////////////////////////////////////////////////////////////
474
475 #ifdef USE_ICONV
476
convCharsetSimple(char * str,int direction)477 char * convCharsetSimple(char *str, int direction)
478 {
479 if (!str) return strdup("");
480 size_t size = strlen(str);
481
482 return convCharset(str, size, direction);
483 }
484
convCharset(char * str,size_t size,int direction)485 char * convCharset(char *str, size_t size, int direction)
486 {
487 DEBUG2("convCharset >%s<", str);
488 char *out;
489
490 if (!str || size == 0 ||
491 (direction == CNV_TO && convertorTo == (iconv_t) - 1) ||
492 (direction == CNV_FROM && convertorFrom == (iconv_t) - 1)) {
493
494 DEBUG2("convCharset skip conversion");
495 out = strdup("");
496
497 } else {
498
499 char *buf, *holder;
500 size_t insize, outsize, bufsize, r;
501
502 insize = size;
503 outsize = bufsize = insize * 4;
504
505 buf = (char *) malloc(bufsize);
506 holder = buf;
507
508 iconv_t cnv = (direction == CNV_TO ? convertorTo : convertorFrom);
509
510 r = iconv(cnv, &str, &insize, &buf, &outsize);
511 if (r < 0 || insize != 0) {
512 DEBUG2("convCharset error on conversion %d", (int) outsize);
513 free(holder);
514 return strdup("");
515 }
516
517
518 size = bufsize - outsize;
519
520 buf -= size;
521 out = (char *) malloc(size + 1);
522 memcpy(out, buf, size);
523 out[size] = '\0';
524
525 free(holder);
526 }
527
528 return out;
529 }
530
531 #endif
532
533 //////////////////////////////////////////////////////////////////////////////////
534