Added internal-lirc-backend and stuff.
[irreco.git] / backend / internal-lirc / src / backend_internal_lirc.c
blob146a4ca8e98aa0c6f47aea5765547db9264c5c5b
1 /*
2 internal_lirc_backend
3 Copyright (C) 2006 Kimmo Leppälä (kimmo.leppala@gmail.com)
4 Modified 2009 by Sami Mäki (kasmra@xob.kapsi.fi)
6 This is based on the original ir-send program by Christoph Bartelmus
7 (lirc@bartelmus.de)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "backend_internal_lirc.h"
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <netdb.h>
33 #include <time.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <fcntl.h>
38 #include <getopt.h>
39 #include <sys/stat.h>
40 #include <sys/un.h>
41 #include <errno.h>
42 #include <signal.h>
43 #include <limits.h>
44 #include <netinet/in.h>
46 #define PACKET_SIZE 256
47 /* three seconds */
48 #define TIMEOUT 3
50 int timeout = 0;
51 char *progname = "internal_lirc backend";
53 void sigalrm(int sig)
55 timeout = 1;
58 #include <sys/time.h>
60 * From gcc manual
62 int input_timeout(int filedes, unsigned int seconds)
64 fd_set set;
65 struct timeval timeout;
67 /* Initialize the file descriptor set. */
68 FD_ZERO (&set);
69 FD_SET (filedes, &set);
71 /* Initialize the timeout data structure. */
72 timeout.tv_sec = seconds;
73 timeout.tv_usec = 0;
75 /* select returns 0 if timeout, 1 if input available, -1 if error. */
76 return select(FD_SETSIZE, &set, NULL, NULL, &timeout);
79 IrrecoBackendStatus read_string(
80 IrrecoInternalLircBackend *internal_lirc_backend,
81 const char ** string)
83 static char buffer[PACKET_SIZE + 1] = "";
84 char *end;
85 static int ptr = 0;
86 ssize_t ret;
87 IRRECO_ENTER
89 if (ptr > 0) {
90 memmove(buffer, buffer + ptr, strlen(buffer + ptr) + 1);
91 ptr = strlen(buffer);
92 end = strchr(buffer, '\n');
93 } else {
94 end = NULL;
97 while (end == NULL) {
98 if (PACKET_SIZE <= ptr) {
99 ptr = 0;
100 *string = NULL;
101 IRRECO_RETURN_INT(internal_lirc_backend_error(
102 internal_lirc_backend,
103 INTERNAL_LIRC_BACKEND_ERR_BAD_PACKET));
106 if (input_timeout(internal_lirc_backend->socket, 3) < 1) {
107 ptr = 0;
108 *string = NULL;
109 IRRECO_RETURN_INT(internal_lirc_backend_error(
110 internal_lirc_backend,
111 INTERNAL_LIRC_BACKEND_ERR_TIMEOUT));;
112 } else {
113 ret = read(internal_lirc_backend->socket, buffer + ptr,
114 PACKET_SIZE - ptr);
117 buffer[ptr + ret] = 0;
118 ptr = strlen(buffer);
119 end = strchr(buffer, '\n');
122 end[0] = 0;
123 ptr = strlen(buffer) + 1;
124 IRRECO_DEBUG("Input buffer \"%s\".\n", buffer);
125 *string = buffer;
126 IRRECO_RETURN_INT(IRRECO_BACKEND_OK);
129 enum packet_state {
130 P_BEGIN,
131 P_MESSAGE,
132 P_STATUS,
133 P_DATA,
134 P_N,
135 P_DATA_N,
136 P_END
139 IrrecoBackendStatus send_packet(IrrecoInternalLircBackend * internal_lirc_backend,
140 const char *packet,
141 InternalLircBackendResponseHandler handler)
143 int done, todo;
144 const char *string, *data;
145 char *endptr;
146 enum packet_state state;
147 int status, n;
148 unsigned long data_n = 0;
149 IrrecoBackendStatus read_string_status;
150 IRRECO_ENTER
152 IRRECO_PRINTF("Sending packet: \"%s\".\n", packet);
154 todo = strlen(packet);
155 data = packet;
156 while (todo > 0) {
157 done = write(internal_lirc_backend->socket, (void *) data, todo);
158 if (done < 0) {
159 IRRECO_RETURN_INT(internal_lirc_backend_error(
160 internal_lirc_backend,
161 INTERNAL_LIRC_BACKEND_ERR_COULD_NOT_SEND_PACKET,
162 packet));
164 data += done;
165 todo -= done;
168 /* get response */
169 status = 0;
170 state = P_BEGIN;
171 n = 0;
172 while (1) {
174 read_string_status = read_string(internal_lirc_backend,
175 &string);
176 if (read_string_status != IRRECO_BACKEND_OK) {
177 IRRECO_RETURN_INT(read_string_status);
180 switch (state) {
181 case P_BEGIN:
182 if (strcasecmp(string, "BEGIN") != 0) {
183 continue;
185 state = P_MESSAGE;
186 break;
188 case P_MESSAGE:
189 if (strncasecmp(string, packet, strlen(string)) != 0 ||
190 strlen(string) + 1 != strlen(packet)) {
191 state = P_BEGIN;
192 continue;
194 state = P_STATUS;
195 break;
197 case P_STATUS:
198 if (strcasecmp(string, "SUCCESS") == 0) {
199 status = 0;
200 } else if (strcasecmp(string, "END") == 0) {
201 status = 0;
202 goto check_status_code;
203 } else if (strcasecmp(string, "ERROR") == 0) {
204 status = INTERNAL_LIRC_BACKEND_ERR_COMMAND_FAILED;
205 } else {
206 status = INTERNAL_LIRC_BACKEND_ERR_BAD_PACKET;
207 goto check_status_code;
209 state = P_DATA;
210 break;
212 case P_DATA:
213 if (strcasecmp(string, "END") == 0) {
214 goto check_status_code;
215 } else if (strcasecmp(string, "DATA") == 0) {
216 state = P_N;
217 break;
219 status = INTERNAL_LIRC_BACKEND_ERR_BAD_PACKET;
220 goto check_status_code;
222 case P_N:
223 errno = 0;
224 data_n = strtoul(string, &endptr, 0);
225 if (!*string || *endptr) {
226 status = INTERNAL_LIRC_BACKEND_ERR_BAD_PACKET;
227 goto check_status_code;
229 if (data_n == 0) {
230 state = P_END;
231 } else {
232 state = P_DATA_N;
234 break;
236 case P_DATA_N:
237 IRRECO_DEBUG("Response data: \"%s\".\n", string);
238 if (handler != NULL) handler(internal_lirc_backend, string);
239 n++;
240 if (n == data_n) state = P_END;
241 break;
243 case P_END:
244 if (strcasecmp(string, "END") == 0) {
245 goto check_status_code;
247 status = INTERNAL_LIRC_BACKEND_ERR_BAD_PACKET;
248 goto check_status_code;
249 break;
253 check_status_code:
254 switch (status) {
255 case INTERNAL_LIRC_BACKEND_ERR_BAD_PACKET:
256 IRRECO_RETURN_INT(internal_lirc_backend_error(
257 internal_lirc_backend,
258 INTERNAL_LIRC_BACKEND_ERR_BAD_PACKET));
260 case INTERNAL_LIRC_BACKEND_ERR_COMMAND_FAILED:
261 IRRECO_RETURN_INT(internal_lirc_backend_error(
262 internal_lirc_backend,
263 INTERNAL_LIRC_BACKEND_ERR_COMMAND_FAILED, packet));
265 case IRRECO_BACKEND_OK:
266 IRRECO_RETURN_INT(IRRECO_BACKEND_OK);
268 default:
269 IRRECO_ERROR("Weird return code \"%i\"\n", status);
270 IRRECO_RETURN_INT(status);
274 static IrrecoBackendStatus internal_lirc_backend_create_device(
275 gpointer instance_context,
276 GtkWindow *parent)
278 IRRECO_ENTER
279 /* irreco_info_dlg(GTK_WINDOW(parent),
280 "Feature not implemented."); */
281 IRRECO_RETURN_INT(IRRECO_BACKEND_OK);
284 static gboolean internal_lirc_backend_is_device_editable(
285 gpointer instance_context,
286 const gchar *device_name,
287 gpointer device_contex)
289 gboolean retval = TRUE;
290 IRRECO_ENTER
291 IRRECO_RETURN_BOOL(retval);
294 static IrrecoBackendStatus internal_lirc_backend_edit_device(
295 gpointer instance_context,
296 const gchar *device_name,
297 gpointer device_contex,
298 GtkWindow *parent)
300 IRRECO_ENTER
301 irreco_info_dlg(GTK_WINDOW(parent),
302 "Feature not implemented.");
303 IRRECO_RETURN_INT(IRRECO_BACKEND_OK);
306 static IrrecoBackendStatus internal_lirc_delete_device(
307 gpointer instance_context,
308 const char *device_name,
309 gpointer device_contex,
310 GtkWindow *parent)
312 IrrecoBackendStatus status = IRRECO_BACKEND_OK;
313 IrrecoInternalLircBackend *internal_lirc_backend = instance_context;
314 gchar *delete_cmd = NULL;
315 IRRECO_ENTER
317 delete_cmd = g_strdup_printf(
318 "%s%s\"$//g' %s > /tmp/lircd.conf.temporary\
319 && cp /tmp/lircd.conf.temporary %s;\
320 rm /tmp/lircd.conf.temporary",
321 "sed -e \'s/^include.*", device_name,
322 INTERNAL_LIRC_LIRCD_CONF_PATH,
323 INTERNAL_LIRC_LIRCD_CONF_PATH);
325 system(delete_cmd);
327 switch(status) {
328 case IRRECO_BACKEND_OK:
329 IRRECO_RETURN_INT(IRRECO_BACKEND_OK);
331 case INTERNAL_LIRC_BACKEND_ERR_COULD_NOT_DELETE_DEVICE:
332 IRRECO_RETURN_INT(
333 INTERNAL_LIRC_BACKEND_ERR_COULD_NOT_DELETE_DEVICE);
335 default:
336 IRRECO_ERROR("Weird return code \"%i\"\n", status);
337 IRRECO_RETURN_INT(status);
339 g_free(delete_cmd);
341 /* TODO Just testing FIXME */
342 if(!status) {
343 g_print("errmsg: %s\n", internal_lirc_backend->error_msg->str);
344 IRRECO_RETURN_INT(
345 INTERNAL_LIRC_BACKEND_ERR_COULD_NOT_DELETE_DEVICE);
347 else IRRECO_RETURN_INT(status);
351 IrrecoBackendStatus internal_lirc_export_conf(gpointer instance_context,
352 const char *device_name,
353 IrrecoBackendFileContainer **file_container)
355 IrrecoBackendStatus status = IRRECO_BACKEND_OK;
356 gchar *file_data = NULL;
357 gboolean success = TRUE;
358 GString *file_name = g_string_new("");
359 GString *file_path = g_string_new(INTERNAL_LIRC_REMOTES_DIR);
360 IRRECO_ENTER
362 g_string_append_printf(file_name, "%s", device_name);
363 g_string_append_printf(file_path, "/%s", file_name->str);
365 success = g_file_get_contents(file_path->str, &file_data, NULL, NULL);
366 if (success == FALSE) {
367 status = INTERNAL_LIRC_BACKEND_ERR_FILE_OPEN_FAILED;
368 goto clean;
371 *file_container = irreco_backend_file_container_new();
372 irreco_backend_file_container_set(*file_container,
373 "Internal Lirc", /*backend*/
374 NULL, /*category*/
375 NULL, /*manufacturer*/
376 device_name, /*model*/
377 file_name->str, /*name*/
378 file_data); /*data*/
380 clean:
381 g_free(file_data);
382 g_string_free(file_name, TRUE);
383 g_string_free(file_path, TRUE);
385 IRRECO_RETURN_ENUM(status);
388 IrrecoBackendStatus internal_lirc_import_conf(gpointer instance_context,
389 IrrecoBackendFileContainer *file_container)
391 gssize length;
392 gboolean success;
393 GString *file_path = g_string_new(INTERNAL_LIRC_REMOTES_DIR);
394 gchar *sys_cmd = NULL;
395 IRRECO_ENTER
396 length = strlen(file_container->data->str);
398 g_string_append_printf(file_path, "/%s", file_container->name->str);
400 /* Create directory/directories for Lirc devices, if needed. */
401 if(irreco_is_dir(INTERNAL_LIRC_BASE_DIR) == FALSE) {
402 if (g_mkdir(INTERNAL_LIRC_BASE_DIR, 0700) != 0) {
403 IRRECO_RETURN_ENUM(
404 INTERNAL_LIRC_BACKEND_ERR_COULD_NOT_CREATE_BASE_DIR);
408 if(irreco_is_dir(INTERNAL_LIRC_REMOTES_DIR) == FALSE) {
409 if (g_mkdir(INTERNAL_LIRC_REMOTES_DIR, 0700) != 0) {
410 IRRECO_RETURN_ENUM(
411 INTERNAL_LIRC_BACKEND_ERR_COULD_NOT_CREATE_DEVICE_DIR);
415 /* irreco_write_file from irreco_util.h */
416 success = irreco_write_file(file_path->str,
417 file_container->data->str, length);
419 /* Echo include cmd to lircd.conf */
420 sys_cmd = g_strdup_printf("%s '%s \"%s\"' >> %s", "echo", "include",
421 file_path->str, INTERNAL_LIRC_LIRCD_CONF_PATH);
423 system(sys_cmd);
425 g_string_free(file_path, TRUE);
426 g_free(sys_cmd);
428 if(!success){
430 IRRECO_RETURN_ENUM(INTERNAL_LIRC_BACKEND_ERR_CONFIG_WRITE_FAILED);
433 IRRECO_RETURN_ENUM(IRRECO_BACKEND_OK);
436 IrrecoBackendStatus internal_lirc_check_conf(
437 gpointer instance_context,
438 IrrecoBackendFileContainer *file_container,
439 gboolean *configuration)
441 GString *file_path = g_string_new(INTERNAL_LIRC_REMOTES_DIR);
442 IRRECO_ENTER
443 g_string_append_printf(file_path, "/%s", file_container->name->str);
445 /* irreco_file_exists from irreco_util.h */
446 *configuration = irreco_file_exists(file_path->str);
448 g_string_free(file_path, TRUE);
450 IRRECO_RETURN_ENUM(IRRECO_BACKEND_OK);
453 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
454 /* IRRECO PLUGIN API. */
455 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
457 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
458 /* Construction & Destruction. */
459 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
461 IrrecoBackendFunctionTable internal_lirc_backend_function_table = {
462 IRRECO_BACKEND_API_VERSION, /* backend_api_version */
463 IRRECO_BACKEND_EDITABLE_DEVICES |
464 IRRECO_BACKEND_CONFIGURATION_EXPORT |
465 IRRECO_BACKEND_MULTI_DEVICE_SUPPORT
466 /* 0 */, /* flags */
467 "Internal Lirc", /* name */
469 internal_lirc_backend_get_error_msg, /* get_error_msg */
470 internal_lirc_backend_create, /* create */
471 internal_lirc_backend_destroy, /* destroy */
472 internal_lirc_backend_read_from_conf, /* from_conf */
473 internal_lirc_backend_save_to_conf, /* to_conf */
474 internal_lirc_backend_get_devices, /* get_devices */
475 internal_lirc_backend_get_commands, /* get_commands */
476 internal_lirc_backend_send_command, /* send_command */
477 internal_lirc_backend_configure, /* configure */
478 internal_lirc_backend_get_description, /* get_description */
480 internal_lirc_backend_create_device, /* create_device, optional */
481 internal_lirc_backend_is_device_editable,/* is_device_editable, optional */
482 internal_lirc_backend_edit_device, /* edit_device, optional */
483 internal_lirc_delete_device, /* delete_device, optional */
485 internal_lirc_export_conf, /* export_conf, optional */
486 internal_lirc_import_conf, /* import_conf, optional */
487 internal_lirc_check_conf, /* check_conf, optional */
489 NULL
492 IrrecoBackendFunctionTable *get_irreco_backend_function_table()
494 IRRECO_ENTER
495 IRRECO_RETURN_PTR(&internal_lirc_backend_function_table);
498 void* internal_lirc_backend_create()
500 IrrecoInternalLircBackend * internal_lirc_backend;
501 IRRECO_ENTER
503 internal_lirc_backend = g_slice_new0(IrrecoInternalLircBackend);
504 internal_lirc_backend->host = g_string_new("localhost");
505 internal_lirc_backend->port = 8765;
506 internal_lirc_backend->socket = -1;
507 internal_lirc_backend->error_msg = g_string_new(NULL);
508 IRRECO_RETURN_PTR(internal_lirc_backend);
511 void internal_lirc_backend_destroy(gpointer instance_context, gboolean permanently)
513 IrrecoInternalLircBackend * internal_lirc_backend = instance_context;
514 IRRECO_ENTER
516 g_string_free(internal_lirc_backend->host, TRUE);
517 g_string_free(internal_lirc_backend->error_msg, TRUE);
518 g_slice_free(IrrecoInternalLircBackend, internal_lirc_backend);
520 IRRECO_RETURN
525 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
526 /* Error handling. */
527 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
529 const gchar *internal_lirc_backend_get_error_msg(gpointer instance_context,
530 IrrecoBackendStatus code)
532 IrrecoInternalLircBackend * internal_lirc_backend = instance_context;
533 IRRECO_ENTER
534 IRRECO_RETURN_PTR(internal_lirc_backend->error_msg->str);
537 gint internal_lirc_backend_error(IrrecoInternalLircBackend
538 *internal_lirc_backend,
539 IrrecoInternalLircBackendError code, ...)
541 va_list args;
542 gchar *format;
543 gchar *message;
544 IRRECO_ENTER
546 internal_lirc_backend_disconnect(internal_lirc_backend);
548 /* Select message format. */
549 switch (code) {
550 case INTERNAL_LIRC_BACKEND_ERR_CANT_OPEN_SOCKET:
551 format = _("Can not open socket.");
552 break;
554 case INTERNAL_LIRC_BACKEND_ERR_CANT_CONNECT:
555 format = _("Can not connect to internal LIRC server.");
556 break;
558 case INTERNAL_LIRC_BACKEND_ERR_CANT_RESOLVE_HOST:
559 format = _("Can not resolve hostname \"%s\".");
560 break;
562 case INTERNAL_LIRC_BACKEND_ERR_CONFIG_WRITE_FAILED:
563 format = _("Failed to save configuration to file.");
564 break;
566 case INTERNAL_LIRC_BACKEND_ERR_CONFIG_READ_FAILED:
567 format = _("Failed to read configuration from file.");
568 break;
570 case INTERNAL_LIRC_BACKEND_ERR_BAD_PACKET:
571 format = _("Bad return packet");
572 break;
574 case INTERNAL_LIRC_BACKEND_ERR_COULD_NOT_SEND_PACKET:
575 format = _("Could not send packet \"%s\".");
576 break;
578 case INTERNAL_LIRC_BACKEND_ERR_COMMAND_FAILED:
579 format = _("Command \"%s\" failed.");
580 break;
582 case INTERNAL_LIRC_BACKEND_ERR_TIMEOUT:
583 format = _("Timeout while waiting for the server to respond.");
584 break;
586 case INTERNAL_LIRC_BACKEND_ERR_FILE_OPEN_FAILED:
587 format = _("Failed to open file.");
588 break;
590 case INTERNAL_LIRC_BACKEND_ERR_COULD_NOT_CREATE_DEVICE_DIR:
591 format = _("Failed to create device directory.");
592 break;
594 case INTERNAL_LIRC_BACKEND_ERR_COULD_NOT_CREATE_BASE_DIR:
595 format = _("Failed to create base directory.");
596 break;
598 case INTERNAL_LIRC_BACKEND_ERR_COULD_NOT_DELETE_DEVICE:
599 format = _("Failed to delete device.");
600 break;
602 default:
603 g_string_set_size(internal_lirc_backend->error_msg, 0);
604 g_string_append_printf(internal_lirc_backend->error_msg,
605 _("Unknown error code \"%i\"."), code);
606 IRRECO_PRINTF("Error: %s\n",
607 internal_lirc_backend->error_msg->str);
608 IRRECO_RETURN_INT(code);
609 break;
612 va_start(args, code);
613 g_vasprintf(&message, format, args);
614 va_end(args);
616 g_string_set_size(internal_lirc_backend->error_msg, 0);
617 g_string_append(internal_lirc_backend->error_msg, message);
618 g_free(message);
620 /* Print error and return code. */
621 IRRECO_PRINTF("Error: %s\n", internal_lirc_backend->error_msg->str);
622 IRRECO_RETURN_INT(code);
627 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
628 /* Configuration writing and reading. */
629 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
631 IrrecoBackendStatus internal_lirc_backend_read_from_conf(
632 gpointer instance_context, const gchar * config_file)
634 gint port;
635 gint rvalue;
636 gchar *dir = NULL;
637 gchar *host = NULL;
638 IrrecoKeyFile *keyfile = NULL;
639 IrrecoInternalLircBackend * internal_lirc_backend = instance_context;
640 IRRECO_ENTER
642 IRRECO_DEBUG("Reading config file \"%s\".\n", config_file);
643 dir = g_path_get_dirname(config_file);
644 keyfile = irreco_keyfile_create(dir, config_file, "internal_lirc");
646 /* Attempt to read values from keyfile. */
647 if (keyfile == NULL
648 || irreco_keyfile_get_int(keyfile, "port", &port) == FALSE
649 || irreco_keyfile_get_str(keyfile, "host", &host) == FALSE) {
650 IRRECO_PRINTF("Config read failed\n");
651 rvalue = internal_lirc_backend_error(
652 internal_lirc_backend,
653 INTERNAL_LIRC_BACKEND_ERR_CONFIG_READ_FAILED);
655 /* Save values to instace if read succeeded. */
656 } else {
657 IRRECO_PRINTF("Host \"%s\"\n", host);
658 IRRECO_PRINTF("Port \"%i\"\n", port);
660 internal_lirc_backend->port = port;
661 g_string_set_size(internal_lirc_backend->host, 0);
662 g_string_append(internal_lirc_backend->host, host);
663 rvalue = IRRECO_BACKEND_OK;
666 /* Creanup, and return status code. */
667 irreco_keyfile_destroy(keyfile);
668 g_free(host);
669 g_free(dir);
670 IRRECO_RETURN_INT(rvalue);
675 IrrecoBackendStatus internal_lirc_backend_save_to_conf(
676 gpointer instance_context, const gchar * config_file)
678 gboolean success;
679 GKeyFile *keyfile;
680 gchar group[] = "internal_lirc";
681 IrrecoInternalLircBackend * internal_lirc_backend = instance_context;
682 IRRECO_ENTER
684 IRRECO_DEBUG("Saving config file \"%s\".\n", config_file);
686 keyfile = g_key_file_new();
687 g_key_file_set_string(keyfile, group, "host",
688 internal_lirc_backend->host->str);
689 g_key_file_set_integer(keyfile, group, "port",
690 internal_lirc_backend->port);
692 success = irreco_write_keyfile(keyfile, config_file);
693 g_key_file_free(keyfile);
695 if (success == TRUE) {
696 IRRECO_RETURN_INT(IRRECO_BACKEND_OK);
698 IRRECO_RETURN_INT(internal_lirc_backend_error(
699 internal_lirc_backend,
700 INTERNAL_LIRC_BACKEND_ERR_CONFIG_WRITE_FAILED));
705 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
706 /* Connection handling. */
707 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
709 int internal_lirc_backend_connect(IrrecoInternalLircBackend
710 *internal_lirc_backend)
712 struct hostent *host;
713 struct sockaddr_in addr;
714 IRRECO_ENTER
716 IRRECO_PRINTF("Connecting to internal LIRC server.\n");
717 IRRECO_PRINTF("Hostname: \"%s\".\n", internal_lirc_backend->host->str);
718 IRRECO_PRINTF("Port: \"%i\".\n", internal_lirc_backend->port);
720 /* Get host IP. */
721 memset( &addr, '\0', sizeof(addr));
722 if ((host = gethostbyname(internal_lirc_backend->host->str)) == NULL) {
723 IRRECO_RETURN_INT(internal_lirc_backend_error(
724 internal_lirc_backend,
725 INTERNAL_LIRC_BACKEND_ERR_CANT_RESOLVE_HOST,
726 internal_lirc_backend->host->str));
729 /* Create socket. */
730 addr.sin_family = AF_INET;
731 addr.sin_port = htons(internal_lirc_backend->port);
732 memcpy((gpointer) &addr.sin_addr, (gpointer) host->h_addr_list[0],
733 (size_t) host->h_length);
734 if ((internal_lirc_backend->socket = socket(
735 PF_INET, SOCK_STREAM, 0)) == -1) {
736 IRRECO_RETURN_INT(internal_lirc_backend_error(
737 internal_lirc_backend,
738 INTERNAL_LIRC_BACKEND_ERR_CANT_OPEN_SOCKET));
741 /* Connect socket. */
742 if (connect(internal_lirc_backend->socket, (struct sockaddr *) &addr,
743 sizeof(addr)) == -1) {
744 IRRECO_RETURN_INT(internal_lirc_backend_error(
745 internal_lirc_backend,
746 INTERNAL_LIRC_BACKEND_ERR_CANT_OPEN_SOCKET));
749 IRRECO_PRINTF("Connected to internal LIRC server.\n");
750 IRRECO_RETURN_INT(IRRECO_BACKEND_OK);
753 void internal_lirc_backend_disconnect(IrrecoInternalLircBackend
754 *internal_lirc_backend)
756 IRRECO_ENTER
757 if (internal_lirc_backend->socket != -1) {
758 close(internal_lirc_backend->socket);
759 internal_lirc_backend->socket = -1;
761 IRRECO_RETURN
766 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
767 /* Device list . */
768 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
770 IrrecoBackendStatus internal_lirc_backend_get_devices(gpointer instance_context,
771 IrrecoGetDeviceCallback callback)
773 gint rvalue;
774 IrrecoInternalLircBackend * internal_lirc_backend = instance_context;
775 gchar *sys_cmd = NULL;
776 gchar *clean_cmd = NULL;
777 GDir *lirc_device_dir = NULL;
778 const gchar *device_file = "";
779 IRRECO_ENTER
781 system("cat /dev/null > /home/user/.irreco/lircd.conf");
783 /* Scan INTERNAL_LIRC_REMOTES_DIR for available devices and
784 * echo them into lircd.conf */
785 lirc_device_dir = g_dir_open(
786 INTERNAL_LIRC_REMOTES_DIR,
787 0, NULL);
788 while(device_file != NULL) {
789 device_file = g_dir_read_name(lirc_device_dir);
790 sys_cmd = g_strdup_printf(
791 "echo 'include \"%s/%s\"' >> %s",
792 INTERNAL_LIRC_REMOTES_DIR,
793 device_file,
794 INTERNAL_LIRC_LIRCD_CONF_PATH);
795 system(sys_cmd);
797 g_dir_close(lirc_device_dir);
799 /* Remove (null) device from lircd.conf */
800 clean_cmd = g_strdup_printf(
801 "%s//g' %s > /tmp/lircd.conf.temporary\
802 && cp /tmp/lircd.conf.temporary %s;\
803 rm /tmp/lircd.conf.temporary",
804 "sed -e \'s/.*(null)\"$",
805 INTERNAL_LIRC_LIRCD_CONF_PATH,
806 INTERNAL_LIRC_LIRCD_CONF_PATH);
808 system(clean_cmd);
810 g_free(sys_cmd);
811 g_free(clean_cmd);
813 system("sudo /etc/init.d/lirc reload");
815 rvalue = internal_lirc_backend_connect(internal_lirc_backend);
816 if (rvalue) IRRECO_RETURN_INT(rvalue);
818 internal_lirc_backend->dev_callback = callback;
819 rvalue = send_packet(internal_lirc_backend, "LIST\n",
820 internal_lirc_backend_get_device_responce);
821 internal_lirc_backend->dev_callback = NULL;
822 if (rvalue) IRRECO_RETURN_INT(rvalue);
824 internal_lirc_backend_disconnect(internal_lirc_backend);
825 IRRECO_RETURN_INT(IRRECO_BACKEND_OK);
827 void internal_lirc_backend_get_device_responce(IrrecoInternalLircBackend
828 *internal_lirc_backend,
829 const gchar * response)
831 IRRECO_ENTER
832 IRRECO_PRINTF("Device: \"%s\"\n", response);
833 internal_lirc_backend->dev_callback(response, NULL);
834 IRRECO_RETURN
837 IrrecoBackendStatus internal_lirc_backend_get_commands(gpointer instance_context,
838 const gchar * device_name,
839 gpointer device_contex,
840 IrrecoGetCommandCallback callback)
842 int rvalue;
843 GString *packet;
844 IrrecoInternalLircBackend * internal_lirc_backend = instance_context;
845 IRRECO_ENTER
847 rvalue = internal_lirc_backend_connect(internal_lirc_backend);
848 if (rvalue) IRRECO_RETURN_INT(rvalue);
850 internal_lirc_backend->cmd_callback = callback;
851 packet = g_string_new(NULL);
852 g_string_append_printf(packet, "LIST %s\n", device_name);
853 rvalue = send_packet(internal_lirc_backend, packet->str,
854 internal_lirc_backend_get_command_responce);
855 g_string_free(packet, TRUE);
856 internal_lirc_backend->cmd_callback = NULL;
857 if (rvalue) IRRECO_RETURN_INT(rvalue);
859 internal_lirc_backend_disconnect(internal_lirc_backend);
860 IRRECO_RETURN_INT(IRRECO_BACKEND_OK);
862 void internal_lirc_backend_get_command_responce(IrrecoInternalLircBackend
863 *internal_lirc_backend,
864 const gchar * response)
866 gint pos;
867 IRRECO_ENTER
869 IRRECO_PRINTF("Command: \"%s\"\n", response);
870 if ((pos = irreco_char_pos(response, ' ')) == -1) {
871 internal_lirc_backend->cmd_callback(response, NULL);
872 } else {
873 internal_lirc_backend->cmd_callback(response + pos + 1, NULL);
875 IRRECO_RETURN
878 gchar *internal_lirc_backend_get_description(gpointer instance_context)
880 IrrecoInternalLircBackend * internal_lirc_backend = instance_context;
881 IRRECO_ENTER
882 IRRECO_RETURN_PTR(g_strdup(internal_lirc_backend->host->str));
886 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
887 /* Command sending. */
888 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
890 IrrecoBackendStatus internal_lirc_backend_send_command(gpointer instance_context,
891 const gchar * device_name,
892 gpointer device_contex,
893 const gchar * command_name,
894 gpointer command_contex)
896 int rvalue;
897 GString *packet;
898 IrrecoInternalLircBackend * internal_lirc_backend = instance_context;
899 IRRECO_ENTER
901 rvalue = internal_lirc_backend_connect(internal_lirc_backend);
902 if (rvalue) IRRECO_RETURN_INT(rvalue);
904 packet = g_string_new(NULL);
905 g_string_append_printf(packet, "SEND_ONCE %s %s\n",
906 device_name, command_name);
907 rvalue = send_packet(internal_lirc_backend, packet->str, NULL);
908 g_string_free(packet, TRUE);
909 if (rvalue) IRRECO_RETURN_INT(rvalue);
911 internal_lirc_backend_disconnect(internal_lirc_backend);
912 IRRECO_RETURN_INT(IRRECO_BACKEND_OK);
917 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
918 /* Configuration dialog. */
919 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
922 * Create label, align it, and insert it into a table.
924 void internal_lirc_backend_dlg_insert_label(GtkWidget *table,
925 const gchar *str,
926 guint l,
927 guint r,
928 guint t,
929 guint b)
931 GtkWidget *label;
932 IRRECO_ENTER
933 label = gtk_label_new(str);
934 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
935 gtk_table_attach(GTK_TABLE(table), label, l, r, t, b,
936 GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
937 IRRECO_RETURN
940 IrrecoBackendStatus internal_lirc_backend_configure(gpointer instance_context,
941 GtkWindow * parent)
943 IrrecoInternalLircBackend * internal_lirc_backend = instance_context;
944 gint loop = TRUE;
945 GString *port_string;
946 GtkWidget *dialog;
947 GtkWidget *table;
948 GtkWidget *host_entry;
949 GtkWidget *port_entry;
950 IRRECO_ENTER
952 /* Create objects. */
953 dialog = gtk_dialog_new_with_buttons(
954 _("Internal LIRC server configuration"), parent,
955 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT |
956 GTK_DIALOG_NO_SEPARATOR,
957 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
958 /*_("Test"), 100, */
959 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
960 NULL);
961 table = gtk_table_new(2, 2, FALSE);
962 host_entry = gtk_entry_new();
963 port_entry = gtk_entry_new();
965 /* Set values. */
966 gtk_entry_set_text(GTK_ENTRY(host_entry),
967 internal_lirc_backend->host->str);
968 port_string = g_string_new(NULL);
969 g_string_append_printf(port_string, "%i", internal_lirc_backend->port);
970 gtk_entry_set_text(GTK_ENTRY(port_entry), port_string->str);
971 g_string_free(port_string, TRUE);
973 /* Build dialog. */
974 internal_lirc_backend_dlg_insert_label(table, _("Hostname"), 0, 1, 0, 1);
975 gtk_table_attach_defaults(GTK_TABLE(table), host_entry, 1, 2, 0, 1);
976 internal_lirc_backend_dlg_insert_label(table, _("Port"), 0, 1, 1, 2);
977 gtk_table_attach_defaults(GTK_TABLE(table), port_entry, 1, 2, 1, 2);
978 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
979 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
980 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
981 gtk_widget_show_all(dialog);
983 while (loop == TRUE) {
984 switch (gtk_dialog_run(GTK_DIALOG(dialog))) {
985 case GTK_RESPONSE_REJECT:
986 loop = FALSE;
987 break;
989 case GTK_RESPONSE_ACCEPT:
991 long int port;
992 port = strtol(gtk_entry_get_text(GTK_ENTRY(
993 port_entry)), NULL, 10);
994 if (port < 1 || port > 65535) {
995 irreco_error_dlg(GTK_WINDOW(dialog),
996 _("Port number must be "
997 "in range 1 - 65535"));
998 break;
1001 internal_lirc_backend->port = port;
1002 g_string_set_size(internal_lirc_backend->host, 0);
1003 g_string_append(internal_lirc_backend->host,
1004 gtk_entry_get_text(
1005 GTK_ENTRY(host_entry)));
1006 loop = FALSE;
1007 break;
1012 gtk_widget_destroy(dialog);
1013 IRRECO_RETURN_INT(IRRECO_BACKEND_OK);