Stupid autotools.
[mpdcron.git] / main.c
blob96eddc132e79dbd7a28cb9f52903d40b4b97e7c1
1 /* MPDCron
2 * Copyright (C) 2009-2009 Qball Cow <qball@sarine.nl>
3 * Project homepage: http://gmpc.wikia.com/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <mpd/client.h>
24 #include <mpd/async.h>
25 #include <stdbool.h>
26 #include <signal.h>
27 #include <errno.h>
28 #include "do_command.h"
30 typedef struct event_entry {
31 enum mpd_idle event;
32 char *command;
33 }event_entry;
35 unsigned int num_entries = 0;
36 event_entry **entries = NULL;
37 struct mpd_connection *conn = NULL;
39 /* Code borrowed from mpdscribble */
40 static void signal_handler(int signum)
42 mpd_connection_free(conn);
43 conn = NULL;
46 static void
47 x_sigaction(int signum, const struct sigaction *act)
49 if (sigaction(signum, act, NULL) < 0) {
50 perror("sigaction()");
51 exit(EXIT_FAILURE);
55 static void
56 setup_signals(void)
58 struct sigaction sa;
60 sigemptyset(&sa.sa_mask);
61 sa.sa_flags = 0;
62 sa.sa_handler = signal_handler;
63 x_sigaction(SIGINT, &sa);
64 x_sigaction(SIGTERM, &sa);
65 x_sigaction(SIGHUP, &sa);
67 sa.sa_handler = SIG_IGN;
68 x_sigaction(SIGPIPE, &sa);
70 /* Parse the config file, return all the events to watch */
71 static enum mpd_idle parse_cronfile(FILE *fp)
73 enum mpd_idle values_events = 0;
74 char buffer[1024*4];
76 while(fgets(buffer,1024*4, fp) != NULL)
78 int i = 0;
79 for(i =0; buffer[i] != '\0' && buffer[i] != ' '; i++);
80 if(buffer[i] == ' ')
82 enum mpd_idle event=0;
83 char *item;
84 char *saveptr;
85 item = strtok_r(&buffer[0], "|", &saveptr);
86 if(item)do{
87 if(strncmp(item, "PLAYER",strlen("PLAYER")) == 0) event += MPD_IDLE_PLAYER;
88 else if(strncmp(item, "DATABASE",strlen("DATABASE")) == 0) event += MPD_IDLE_DATABASE;
89 else if(strncmp(item, "STORED_PLAYLIST",strlen("STORED_PLAYLIST")) == 0) event += MPD_IDLE_STORED_PLAYLIST;
90 else if(strncmp(item, "QUEUE",strlen("QUEUE")) == 0) event += MPD_IDLE_QUEUE;
91 else if(strncmp(item, "MIXER",strlen("MIXER")) == 0) event += MPD_IDLE_MIXER;
92 else if(strncmp(item, "OUTPUT",strlen("OUTPUT")) == 0) event += MPD_IDLE_OUTPUT;
93 else if(strncmp(item, "OPTIONS",strlen("OPTIONS")) == 0) event += MPD_IDLE_OPTIONS;
94 else if(strncmp(item, "UPDATE",strlen("UPDATE")) == 0) event += MPD_IDLE_UPDATE;
95 item = strtok_r(NULL, "|",&saveptr);
96 }while(item != NULL);
97 num_entries++;
98 entries = realloc(entries, (size_t)(num_entries+1)*sizeof(*entries));
99 entries[num_entries-1] = malloc(sizeof(struct event_entry));
100 entries[num_entries-1]->event = event;
101 entries[num_entries-1]->command = strdup(&buffer[i+1]);
102 entries[num_entries] = NULL;
104 values_events |= event;
107 return values_events;
110 int main (int argc, char **argv)
112 bool daemonize = true;
113 bool file_specified = false;
114 const char *hostname = NULL;
115 int port = 0;
117 unsigned int i;
118 enum mpd_idle idle_event, listen_to_events=0;
121 * Parse the commandline options
123 if(argc >= 2)
125 for(i=1;i<(unsigned int)argc;i++)
127 if(argv[i][0] == '-'){
128 if(strcmp(argv[i], "-f") ==0) daemonize = false;
129 else if (strncmp(argv[i], "--hostname=", 11) == 0){
130 hostname = &(argv[i][11]);
131 } else if (strncmp(argv[i], "--port=", 7) == 0){
132 port = atoi(&(argv[i][7]));
133 } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
134 printf("MPDCRON <OPTIONS> <CONFIG FILE> ...\n\n");
135 printf("-f Do not daemonize\n");
136 printf("--hostname=<name> Set hostname\n");
137 printf("--port=port Set port\n");
138 printf("--help -h Help message\n");
139 exit(EXIT_SUCCESS);
140 } else {
141 fprintf(stderr, "Unknown parameter: %s\n", argv[i]);
142 exit (EXIT_FAILURE);
144 } else {
145 FILE *fp = NULL;
146 /* Open the file */
147 fp = fopen(argv[i], "r");
148 if(!fp) {
149 fprintf(stderr, "Failed to open file: %s: %s\n", argv[i], strerror(errno));
150 exit(EXIT_FAILURE);
152 /* Parse file */
153 listen_to_events |= parse_cronfile(fp);
154 fclose(fp);
155 file_specified = true;
160 * If no file specified try ~/.mpdcron
162 if(!file_specified)
164 FILE *fp = NULL;
165 char buffer[1024];
166 const char *homedir = getenv("HOME");
167 if(homedir == NULL) {
168 fprintf(stderr, "Homedir not found\n");
169 exit(EXIT_FAILURE);
171 /* Create path to config file */
172 snprintf(buffer,1024, "%s/.mpdcron", homedir);
173 /* Open the file */
174 fp = fopen(buffer, "r");
175 if(!fp) {
176 /* not found is fatal here */
177 fprintf(stderr, "No mpdcron file found\n");
178 exit(EXIT_FAILURE);
180 /* Parse file */
181 listen_to_events |= parse_cronfile(fp);
182 fclose(fp);
184 setup_signals();
185 conn = mpd_connection_new(hostname, port, 5000);
187 if(conn == NULL) {
188 fprintf(stderr, "Failed to allocate memory\n");
189 return EXIT_FAILURE;
192 if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) {
193 fprintf(stderr,"%s\n", mpd_connection_get_error_message(conn));
194 mpd_connection_free(conn);
195 conn = NULL;
196 return EXIT_FAILURE;
199 /* Daemonize */
200 if(daemonize) {
201 switch (fork()){
202 case 0:
203 break;
204 case -1:
205 default:
206 exit(EXIT_SUCCESS);
210 /* loop */
211 while(true)
213 idle_event =mpd_run_idle_mask(conn,listen_to_events);
214 if(idle_event == 0) break;
215 for(i=0; i< num_entries; i++){
216 if((idle_event&(entries[i]->event)) != 0) {
217 do_command(entries[i]->command);
221 /* Close/cleanup connection */
222 if(conn)
223 mpd_connection_free(conn);
224 /* Free the entries */
225 for(i=0;i<num_entries;i++) {
226 free(entries[i]->command);
227 free(entries[i]);
229 free(entries);