Code

19dad29873463bf1deeec23a8921ad19d40bde4d
[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 <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     }
110 void
111 exit_and_cleanup(void)
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);
129 void
130 catch_sigint( int sig )
132   printf("\n%s\n", _("Exiting..."));
133   exit(EXIT_SUCCESS);
136 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 #ifdef DEBUG
156 void 
157 D(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   /* 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);
204   
205   /* read configuration */
206   read_configuration(options);
208   /* check key bindings */
209   key_error = check_key_bindings(NULL, NULL, 0);
210   
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);
322           
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);