19dad29873463bf1deeec23a8921ad19d40bde4d
1 /*
2 * $Id$
3 *
4 * (c) 2004 by Kalle Wallin <kaw@linux.se>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <signal.h>
25 #include <string.h>
26 #include <glib.h>
28 #include "config.h"
29 #include "ncmpc.h"
30 #include "mpdclient.h"
31 #include "support.h"
32 #include "options.h"
33 #include "conf.h"
34 #include "command.h"
35 #include "screen.h"
36 #include "screen_utils.h"
37 #include "strfsong.h"
39 #define BUFSIZE 1024
41 static mpdclient_t *mpd = NULL;
42 static gboolean connected = FALSE;
43 static GTimer *timer = NULL;
45 static gchar *
46 error_msg(gchar *msg)
47 {
48 gchar *p;
50 if( (p=strchr(msg, '}' )) == NULL )
51 return msg;
52 while( p && *p && (*p=='}' || *p==' ') )
53 p++;
55 return p;
56 }
58 static void
59 error_callback(mpdclient_t *c, gint error, gchar *msg)
60 {
61 gint code = GET_ACK_ERROR_CODE(error);
63 error = error & 0xFF;
64 D("Error [%d:%d]> \"%s\"\n", error, code, msg);
65 switch(error)
66 {
67 case MPD_ERROR_CONNPORT:
68 case MPD_ERROR_NORESPONSE:
69 break;
70 case MPD_ERROR_ACK:
71 screen_status_printf("%s", error_msg(msg));
72 screen_bell();
73 break;
74 default:
75 screen_status_printf("%s", msg);
76 screen_bell();
77 doupdate();
78 connected = FALSE;
79 }
80 }
82 static void
83 update_xterm_title(void)
84 {
85 static char title[BUFSIZE];
86 char tmp[BUFSIZE];
87 mpd_Status *status = NULL;
88 mpd_Song *song = NULL;
90 if( mpd )
91 {
92 status = mpd->status;
93 song = mpd->song;
94 }
96 if(options.xterm_title_format && status && song && IS_PLAYING(status->state))
97 {
98 strfsong(tmp, BUFSIZE, options.xterm_title_format, song);
99 }
100 else
101 strncpy(tmp, PACKAGE " version " VERSION, BUFSIZE);
103 if( strcmp(title,tmp) )
104 {
105 strncpy(title, tmp, BUFSIZE);
106 set_xterm_title(title);
107 }
108 }
110 void
111 exit_and_cleanup(void)
112 {
113 screen_exit();
114 set_xterm_title("");
115 printf("\n");
116 if( mpd )
117 {
118 mpdclient_disconnect(mpd);
119 mpd = mpdclient_free(mpd);
120 }
121 g_free(options.host);
122 g_free(options.password);
123 g_free(options.list_format);
124 g_free(options.status_format);
125 if( timer )
126 g_timer_destroy(timer);
127 }
129 void
130 catch_sigint( int sig )
131 {
132 printf("\n%s\n", _("Exiting..."));
133 exit(EXIT_SUCCESS);
134 }
136 void
137 catch_sigcont( int sig )
138 {
139 D("catch_sigcont()\n");
140 #ifdef ENABLE_RAW_MODE
141 reset_prog_mode(); /* restore tty modes */
142 refresh();
143 #endif
144 screen_resize();
145 }
147 void
148 sigstop(void)
149 {
150 def_prog_mode(); /* save the tty modes */
151 endwin(); /* end curses mode temporarily */
152 kill(0, SIGSTOP); /* issue SIGSTOP */
153 }
155 #ifdef DEBUG
156 void
157 D(char *format, ...)
158 {
159 if( options.debug )
160 {
161 gchar *msg;
162 va_list ap;
164 va_start(ap,format);
165 msg = g_strdup_vprintf(format,ap);
166 va_end(ap);
167 fprintf(stderr, "%s", msg);
168 g_free(msg);
169 }
170 }
171 #endif
173 int
174 main(int argc, const char *argv[])
175 {
176 options_t *options;
177 struct sigaction act;
178 const char *charset = NULL;
179 gboolean key_error;
181 #ifdef HAVE_LOCALE_H
182 /* time and date formatting */
183 setlocale(LC_TIME,"");
184 /* charset */
185 setlocale(LC_CTYPE,"");
186 /* initialize charset conversions */
187 charset_init(g_get_charset(&charset));
188 D("charset: %s\n", charset);
189 #endif
191 /* initialize i18n support */
192 #ifdef ENABLE_NLS
193 setlocale(LC_MESSAGES, "");
194 bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR);
195 bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
196 textdomain(GETTEXT_PACKAGE);
197 #endif
199 /* initialize options */
200 options = options_init();
202 /* parse command line options - 1 pass get configuration files */
203 options_parse(argc, argv);
205 /* read configuration */
206 read_configuration(options);
208 /* check key bindings */
209 key_error = check_key_bindings(NULL, NULL, 0);
211 /* parse command line options - 2 pass */
212 options_parse(argc, argv);
214 /* setup signal behavior - SIGINT */
215 sigemptyset( &act.sa_mask );
216 act.sa_flags = 0;
217 act.sa_handler = catch_sigint;
218 if( sigaction(SIGINT, &act, NULL)<0 )
219 {
220 perror("signal");
221 exit(EXIT_FAILURE);
222 }
223 /* setup signal behavior - SIGTERM */
224 sigemptyset( &act.sa_mask );
225 act.sa_flags = 0;
226 act.sa_handler = catch_sigint;
227 if( sigaction(SIGTERM, &act, NULL)<0 )
228 {
229 perror("sigaction()");
230 exit(EXIT_FAILURE);
231 }
232 /* setup signal behavior - SIGCONT */
233 sigemptyset( &act.sa_mask );
234 act.sa_flags = 0;
235 act.sa_handler = catch_sigcont;
236 if( sigaction(SIGCONT, &act, NULL)<0 )
237 {
238 perror("sigaction(SIGCONT)");
239 exit(EXIT_FAILURE);
240 }
242 /* install exit function */
243 atexit(exit_and_cleanup);
245 /* connect to our music player daemon */
246 mpd = mpdclient_new();
247 if( mpdclient_connect(mpd,
248 options->host,
249 options->port,
250 10.0,
251 options->password) )
252 {
253 exit(EXIT_FAILURE);
254 }
255 connected = TRUE;
256 D("Connected to MPD version %d.%d.%d\n",
257 mpd->connection->version[0],
258 mpd->connection->version[1],
259 mpd->connection->version[2]);
261 /* quit if mpd is pre 0.11.0 - song id not supported by mpd */
262 if( MPD_VERSION_LT(mpd, 0,11,0) )
263 {
264 fprintf(stderr,
265 _("Error: MPD version %d.%d.%d is to old (0.11.0 needed).\n"),
266 mpd->connection->version[0],
267 mpd->connection->version[1],
268 mpd->connection->version[2]);
269 exit(EXIT_FAILURE);
270 }
272 /* initialize curses */
273 screen_init(mpd);
275 /* install error callback function */
276 mpdclient_install_error_callback(mpd, error_callback);
278 /* initialize timer */
279 timer = g_timer_new();
281 connected = TRUE;
282 while( connected || options->reconnect )
283 {
284 static gdouble t = G_MAXDOUBLE;
286 if( key_error )
287 {
288 char buf[BUFSIZE];
290 key_error=check_key_bindings(NULL, buf, BUFSIZE);
291 screen_status_printf("%s", buf);
292 }
294 if( connected && (t>=MPD_UPDATE_TIME || mpd->need_update) )
295 {
296 mpdclient_update(mpd);
297 g_timer_start(timer);
298 }
300 if( connected )
301 {
302 command_t cmd;
304 screen_update(mpd);
305 if( (cmd=get_keyboard_command()) != CMD_NONE )
306 {
307 screen_cmd(mpd, cmd);
308 if( cmd==CMD_VOLUME_UP || cmd==CMD_VOLUME_DOWN)
309 /* make shure we dont update the volume yet */
310 g_timer_start(timer);
311 }
312 else
313 screen_idle(mpd);
314 }
315 else if( options->reconnect )
316 {
317 screen_status_printf(_("Connecting to %s... [Press %s to abort]"),
318 options->host, get_key_names(CMD_QUIT,0) );
320 if( get_keyboard_command_with_timeout(MPD_RECONNECT_TIME)==CMD_QUIT)
321 exit(EXIT_SUCCESS);
323 if( mpdclient_connect(mpd,
324 options->host,
325 options->port,
326 1.5,
327 options->password) == 0 )
328 {
329 screen_status_printf(_("Connected to %s!"), options->host);
330 connected = TRUE;
331 }
332 doupdate();
333 }
334 if( options->enable_xterm_title )
335 update_xterm_title();
336 t = g_timer_elapsed(timer, NULL);
337 }
338 exit(EXIT_FAILURE);
339 }