Code

c2c7170eb7477461d36fdf92bc4a757c21d3102a
[ncmpc.git] / src / main.c
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     }
111 void
112 exit_and_cleanup(void)
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);
131 void
132 catch_sigint( int sig )
134         printf("\n%s\n", _("Exiting..."));
135         exit(EXIT_SUCCESS);
138 void
139 catch_sigcont( int sig )
141         D("catch_sigcont()\n");
142 #ifdef ENABLE_RAW_MODE
143         reset_prog_mode(); /* restore tty modes */
144         refresh();
145 #endif
146         screen_resize();
149 void
150 sigstop(void)
152   def_prog_mode();  /* save the tty modes */
153   endwin();         /* end curses mode temporarily */
154   kill(0, SIGSTOP); /* issue SIGSTOP */
157 #ifdef DEBUG
158 void 
159 D(char *format, ...)
161   if( options.debug )
162     {
163       gchar *msg;
164       va_list ap;
165   
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     }
173 #endif
175 int
176 main(int argc, const char *argv[])
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);