Code

97bfdd3f96bc2abace0146e570d082e52b8d45b9
[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 "config.h"
22 #include "ncmpc.h"
23 #include "mpdclient.h"
24 #include "support.h"
25 #include "options.h"
26 #include "conf.h"
27 #include "command.h"
28 #include "src_lyrics.h"
29 #include "screen.h"
30 #include "screen_utils.h"
31 #include "strfsong.h"
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <signal.h>
36 #include <string.h>
38 #define BUFSIZE 1024
40 static mpdclient_t   *mpd = NULL;
41 static gboolean connected = FALSE;
42 static GTimer      *timer = NULL;
44 static const gchar *
45 error_msg(const gchar *msg)
46 {
47   gchar *p;
49   if( (p=strchr(msg, '}' )) == NULL )
50     return msg;
51   while( p && *p && (*p=='}' || *p==' ') )
52     p++;
54   return p;
55 }
57 static void
58 error_callback(mpdclient_t *c, gint error, const gchar *msg)
59 {
60         gint code = GET_ACK_ERROR_CODE(error);
62         error = error & 0xFF;
63         D("Error [%d:%d]> \"%s\"\n", error, code, msg);
64         switch (error) {
65         case MPD_ERROR_CONNPORT:
66         case MPD_ERROR_NORESPONSE:
67                 break;
68         case MPD_ERROR_ACK:
69                 screen_status_printf("%s", error_msg(msg));
70                 screen_bell();
71                 break;
72         default:
73                 screen_status_printf("%s", msg);
74                 screen_bell();
75                 doupdate();
76                 connected = FALSE;
77         }
78 }
80 static void
81 update_xterm_title(void)
82 {
83   static char title[BUFSIZE];
84   char tmp[BUFSIZE];
85   mpd_Status *status = NULL;
86   mpd_Song *song = NULL;
88   if( mpd )
89     {
90       status = mpd->status;
91       song = mpd->song;
92     }
94   if(options.xterm_title_format && status && song && IS_PLAYING(status->state))
95     {
96       strfsong(tmp, BUFSIZE, options.xterm_title_format, song);
97     }
98   else
99     g_strlcpy(tmp, PACKAGE " version " VERSION, BUFSIZE);
101   if( strncmp(title,tmp,BUFSIZE) )
102     {
103       g_strlcpy(title, tmp, BUFSIZE);
104       set_xterm_title("%s", title);
105     }
108 static void
109 exit_and_cleanup(void)
111   screen_exit();
112   set_xterm_title("");
113   printf("\n");
114   if( mpd )
115     {
116       mpdclient_disconnect(mpd);
117       mpd = mpdclient_free(mpd);
118     }
119   g_free(options.host);
120   g_free(options.password);
121   g_free(options.list_format);
122   g_free(options.status_format);
123   g_free(options.scroll_sep);
124   if( timer )
125     g_timer_destroy(timer);
128 static void
129 catch_sigint( int sig )
131         printf("\n%s\n", _("Exiting..."));
132         exit(EXIT_SUCCESS);
136 static void
137 catch_sigcont( int sig )
139         D("catch_sigcont()\n");
140 #ifdef ENABLE_RAW_MODE
141         reset_prog_mode(); /* restore tty modes */
142         refresh();
143 #endif
144         screen_resize();
147 void
148 sigstop(void)
150   def_prog_mode();  /* save the tty modes */
151   endwin();         /* end curses mode temporarily */
152   kill(0, SIGSTOP); /* issue SIGSTOP */
155 #ifndef NDEBUG
156 void 
157 D(const char *format, ...)
159   if( options.debug )
160     {
161       gchar *msg;
162       va_list ap;
163   
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     }
171 #endif
173 int
174 main(int argc, const char *argv[])
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         /* care about sorting order etc */
185         setlocale(LC_COLLATE,"");
186         /* charset */
187         setlocale(LC_CTYPE,"");
188         /* initialize charset conversions */
189         charset_init(g_get_charset(&charset));
190         D("charset: %s\n", charset);
191 #endif
193         /* initialize i18n support */
194 #ifdef ENABLE_NLS
195         setlocale(LC_MESSAGES, "");
196         bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR);
197         bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
198         textdomain(GETTEXT_PACKAGE);
199 #endif
201         /* initialize options */
202         options = options_init();
204         /* parse command line options - 1 pass get configuration files */
205         options_parse(argc, argv);
207         /* read configuration */
208         read_configuration(options);
210         /* check key bindings */
211         key_error = check_key_bindings(NULL, NULL, 0);
213         /* parse command line options - 2 pass */
214         options_parse(argc, argv);
216         /* setup signal behavior - SIGINT */
217         sigemptyset( &act.sa_mask );
218         act.sa_flags    = 0;
219         act.sa_handler = catch_sigint;
220         if( sigaction(SIGINT, &act, NULL)<0 ) {
221                 perror("signal");
222                 exit(EXIT_FAILURE);
223         }
225         /* setup signal behavior - SIGTERM */
226         sigemptyset( &act.sa_mask );
227         act.sa_flags    = 0;
228         act.sa_handler = catch_sigint;
229         if( sigaction(SIGTERM, &act, NULL)<0 ) {
230                 perror("sigaction()");
231                 exit(EXIT_FAILURE);
232         }
234         /* setup signal behavior - SIGCONT */
235         sigemptyset( &act.sa_mask );
236         act.sa_flags    = 0;
237         act.sa_handler = catch_sigcont;
238         if( sigaction(SIGCONT, &act, NULL)<0 ) {
239                 perror("sigaction(SIGCONT)");
240                 exit(EXIT_FAILURE);
241         }
243         /* setup signal behaviour - SIGHUP*/
244         sigemptyset( &act.sa_mask );
245         act.sa_flags    = 0;
246         act.sa_handler = catch_sigint;
247         if( sigaction(SIGHUP, &act, NULL)<0 ) {
248                 perror("sigaction(SIGHUP)");
249                 exit(EXIT_FAILURE);
250         }
252         /* install exit function */
253         atexit(exit_and_cleanup);
255         ncurses_init();
257         src_lyr_init ();
259         /* connect to our music player daemon */
260         mpd = mpdclient_new();
262         if (mpdclient_connect(mpd,
263                               options->host,
264                               options->port,
265                               10.0,
266                               options->password))
267                 exit(EXIT_FAILURE);
269         /* if no password is used, but the mpd wants one, the connection
270            might be established but no status information is avaiable */
271         mpdclient_update(mpd);
272         if (!mpd->status)
273                 screen_auth(mpd);
275         if (!mpd->status)
276                 exit(EXIT_FAILURE);
278         connected = TRUE;
279         D("Connected to MPD version %d.%d.%d\n",
280           mpd->connection->version[0],
281           mpd->connection->version[1],
282           mpd->connection->version[2]);
284         /* quit if mpd is pre 0.11.0 - song id not supported by mpd */
285         if( MPD_VERSION_LT(mpd, 0,11,0) ) {
286                 fprintf(stderr,
287                         _("Error: MPD version %d.%d.%d is to old (0.11.0 needed).\n"),
288                         mpd->connection->version[0],
289                         mpd->connection->version[1],
290                         mpd->connection->version[2]);
291                 exit(EXIT_FAILURE);
292         }
294         /* initialize curses */
295         screen_init(mpd);
296         /* install error callback function */
297         mpdclient_install_error_callback(mpd, error_callback);
299         /* initialize timer */
300         timer = g_timer_new();
302         connected = TRUE;
303         while (connected || options->reconnect) {
304                 static gdouble t = G_MAXDOUBLE;
306                 if( key_error ) {
307                         char buf[BUFSIZE];
309                         key_error=check_key_bindings(NULL, buf, BUFSIZE);
310                         screen_status_printf("%s", buf);
311                 }
313                 if( connected && (t>=MPD_UPDATE_TIME || mpd->need_update) ) {
314                         mpdclient_update(mpd);
315                         g_timer_start(timer);
316                 }
318                 if( connected ) {
319                         command_t cmd;
321                         screen_update(mpd);
322                         if( (cmd=get_keyboard_command()) != CMD_NONE )
323                                 {
324                                         screen_cmd(mpd, cmd);
325                                         if( cmd==CMD_VOLUME_UP || cmd==CMD_VOLUME_DOWN)
326                                                 /* make shure we dont update the volume yet */
327                                                 g_timer_start(timer);
328                                 }
329                         else
330                                 screen_idle(mpd);
331                 } else if (options->reconnect) {
332                         screen_status_printf(_("Connecting to %s...  [Press %s to abort]"),
333                                              options->host, get_key_names(CMD_QUIT,0) );
335                         if( get_keyboard_command_with_timeout(MPD_RECONNECT_TIME)==CMD_QUIT)
336                                 exit(EXIT_SUCCESS);
338                         if (mpdclient_connect(mpd,
339                                               options->host, options->port,
340                                               1.5,
341                                               options->password) == 0) {
342                                 screen_status_printf(_("Connected to %s!"), options->host);
343                                 connected = TRUE;
344                         }
346                         doupdate();
347                 }
349                 if (options->enable_xterm_title)
350                         update_xterm_title();
352                 t = g_timer_elapsed(timer, NULL);
353         }
354         exit(EXIT_FAILURE);