c2c7170eb7477461d36fdf92bc4a757c21d3102a
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 <ncurses.h>
27 #include <glib.h>
29 #include "config.h"
30 #include "ncmpc.h"
31 #include "mpdclient.h"
32 #include "support.h"
33 #include "options.h"
34 #include "conf.h"
35 #include "command.h"
36 #include "src_lyrics.h"
37 #include "screen.h"
38 #include "screen_utils.h"
39 #include "strfsong.h"
41 #define BUFSIZE 1024
43 static mpdclient_t *mpd = NULL;
44 static gboolean connected = FALSE;
45 static GTimer *timer = NULL;
47 static gchar *
48 error_msg(gchar *msg)
49 {
50 gchar *p;
52 if( (p=strchr(msg, '}' )) == NULL )
53 return msg;
54 while( p && *p && (*p=='}' || *p==' ') )
55 p++;
57 return p;
58 }
60 static void
61 error_callback(mpdclient_t *c, gint error, gchar *msg)
62 {
63 gint code = GET_ACK_ERROR_CODE(error);
65 error = error & 0xFF;
66 D("Error [%d:%d]> \"%s\"\n", error, code, msg);
67 switch (error) {
68 case MPD_ERROR_CONNPORT:
69 case MPD_ERROR_NORESPONSE:
70 break;
71 case MPD_ERROR_ACK:
72 screen_status_printf("%s", error_msg(msg));
73 screen_bell();
74 break;
75 default:
76 screen_status_printf("%s", msg);
77 screen_bell();
78 doupdate();
79 connected = FALSE;
80 }
81 }
83 static void
84 update_xterm_title(void)
85 {
86 static char title[BUFSIZE];
87 char tmp[BUFSIZE];
88 mpd_Status *status = NULL;
89 mpd_Song *song = NULL;
91 if( mpd )
92 {
93 status = mpd->status;
94 song = mpd->song;
95 }
97 if(options.xterm_title_format && status && song && IS_PLAYING(status->state))
98 {
99 strfsong(tmp, BUFSIZE, options.xterm_title_format, song);
100 }
101 else
102 g_strlcpy(tmp, PACKAGE " version " VERSION, BUFSIZE);
104 if( strncmp(title,tmp,BUFSIZE) )
105 {
106 g_strlcpy(title, tmp, BUFSIZE);
107 set_xterm_title("%s", title);
108 }
109 }
111 void
112 exit_and_cleanup(void)
113 {
114 screen_exit();
115 set_xterm_title("");
116 printf("\n");
117 if( mpd )
118 {
119 mpdclient_disconnect(mpd);
120 mpd = mpdclient_free(mpd);
121 }
122 g_free(options.host);
123 g_free(options.password);
124 g_free(options.list_format);
125 g_free(options.status_format);
126 g_free(options.scroll_sep);
127 if( timer )
128 g_timer_destroy(timer);
129 }
131 void
132 catch_sigint( int sig )
133 {
134 printf("\n%s\n", _("Exiting..."));
135 exit(EXIT_SUCCESS);
136 }
138 void
139 catch_sigcont( int sig )
140 {
141 D("catch_sigcont()\n");
142 #ifdef ENABLE_RAW_MODE
143 reset_prog_mode(); /* restore tty modes */
144 refresh();
145 #endif
146 screen_resize();
147 }
149 void
150 sigstop(void)
151 {
152 def_prog_mode(); /* save the tty modes */
153 endwin(); /* end curses mode temporarily */
154 kill(0, SIGSTOP); /* issue SIGSTOP */
155 }
157 #ifdef DEBUG
158 void
159 D(char *format, ...)
160 {
161 if( options.debug )
162 {
163 gchar *msg;
164 va_list ap;
166 va_start(ap,format);
167 msg = g_strdup_vprintf(format,ap);
168 va_end(ap);
169 fprintf(stderr, "%s", msg);
170 g_free(msg);
171 }
172 }
173 #endif
175 int
176 main(int argc, const char *argv[])
177 {
178 options_t *options;
179 struct sigaction act;
180 const char *charset = NULL;
181 gboolean key_error;
183 #ifdef HAVE_LOCALE_H
184 /* time and date formatting */
185 setlocale(LC_TIME,"");
186 /* care about sorting order etc */
187 setlocale(LC_COLLATE,"");
188 /* charset */
189 setlocale(LC_CTYPE,"");
190 /* initialize charset conversions */
191 charset_init(g_get_charset(&charset));
192 D("charset: %s\n", charset);
193 #endif
195 /* initialize i18n support */
196 #ifdef ENABLE_NLS
197 setlocale(LC_MESSAGES, "");
198 bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR);
199 bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
200 textdomain(GETTEXT_PACKAGE);
201 #endif
203 /* initialize options */
204 options = options_init();
206 /* parse command line options - 1 pass get configuration files */
207 options_parse(argc, argv);
209 /* read configuration */
210 read_configuration(options);
212 /* check key bindings */
213 key_error = check_key_bindings(NULL, NULL, 0);
215 /* parse command line options - 2 pass */
216 options_parse(argc, argv);
218 /* setup signal behavior - SIGINT */
219 sigemptyset( &act.sa_mask );
220 act.sa_flags = 0;
221 act.sa_handler = catch_sigint;
222 if( sigaction(SIGINT, &act, NULL)<0 ) {
223 perror("signal");
224 exit(EXIT_FAILURE);
225 }
227 /* setup signal behavior - SIGTERM */
228 sigemptyset( &act.sa_mask );
229 act.sa_flags = 0;
230 act.sa_handler = catch_sigint;
231 if( sigaction(SIGTERM, &act, NULL)<0 ) {
232 perror("sigaction()");
233 exit(EXIT_FAILURE);
234 }
236 /* setup signal behavior - SIGCONT */
237 sigemptyset( &act.sa_mask );
238 act.sa_flags = 0;
239 act.sa_handler = catch_sigcont;
240 if( sigaction(SIGCONT, &act, NULL)<0 ) {
241 perror("sigaction(SIGCONT)");
242 exit(EXIT_FAILURE);
243 }
245 /* setup signal behaviour - SIGHUP*/
246 sigemptyset( &act.sa_mask );
247 act.sa_flags = 0;
248 act.sa_handler = catch_sigint;
249 if( sigaction(SIGHUP, &act, NULL)<0 ) {
250 perror("sigaction(SIGHUP)");
251 exit(EXIT_FAILURE);
252 }
254 /* install exit function */
255 atexit(exit_and_cleanup);
257 ncurses_init();
259 src_lyr_init ();
261 /* connect to our music player daemon */
262 mpd = mpdclient_new();
264 if (mpdclient_connect(mpd,
265 options->host,
266 options->port,
267 10.0,
268 options->password))
269 exit(EXIT_FAILURE);
271 /* if no password is used, but the mpd wants one, the connection
272 might be established but no status information is avaiable */
273 mpdclient_update(mpd);
274 if (!mpd->status)
275 screen_auth(mpd);
277 if (!mpd->status)
278 exit(EXIT_FAILURE);
280 connected = TRUE;
281 D("Connected to MPD version %d.%d.%d\n",
282 mpd->connection->version[0],
283 mpd->connection->version[1],
284 mpd->connection->version[2]);
286 /* quit if mpd is pre 0.11.0 - song id not supported by mpd */
287 if( MPD_VERSION_LT(mpd, 0,11,0) ) {
288 fprintf(stderr,
289 _("Error: MPD version %d.%d.%d is to old (0.11.0 needed).\n"),
290 mpd->connection->version[0],
291 mpd->connection->version[1],
292 mpd->connection->version[2]);
293 exit(EXIT_FAILURE);
294 }
296 /* initialize curses */
297 screen_init(mpd);
298 /* install error callback function */
299 mpdclient_install_error_callback(mpd, error_callback);
301 /* initialize timer */
302 timer = g_timer_new();
304 connected = TRUE;
305 while (connected || options->reconnect) {
306 static gdouble t = G_MAXDOUBLE;
308 if( key_error ) {
309 char buf[BUFSIZE];
311 key_error=check_key_bindings(NULL, buf, BUFSIZE);
312 screen_status_printf("%s", buf);
313 }
315 if( connected && (t>=MPD_UPDATE_TIME || mpd->need_update) ) {
316 mpdclient_update(mpd);
317 g_timer_start(timer);
318 }
320 if( connected ) {
321 command_t cmd;
323 screen_update(mpd);
324 if( (cmd=get_keyboard_command()) != CMD_NONE )
325 {
326 screen_cmd(mpd, cmd);
327 if( cmd==CMD_VOLUME_UP || cmd==CMD_VOLUME_DOWN)
328 /* make shure we dont update the volume yet */
329 g_timer_start(timer);
330 }
331 else
332 screen_idle(mpd);
333 } else if (options->reconnect) {
334 screen_status_printf(_("Connecting to %s... [Press %s to abort]"),
335 options->host, get_key_names(CMD_QUIT,0) );
337 if( get_keyboard_command_with_timeout(MPD_RECONNECT_TIME)==CMD_QUIT)
338 exit(EXIT_SUCCESS);
340 if (mpdclient_connect(mpd,
341 options->host, options->port,
342 1.5,
343 options->password) == 0) {
344 screen_status_printf(_("Connected to %s!"), options->host);
345 connected = TRUE;
346 }
348 doupdate();
349 }
351 if (options->enable_xterm_title)
352 update_xterm_title();
354 t = g_timer_elapsed(timer, NULL);
355 }
356 exit(EXIT_FAILURE);
357 }