From: <li...@yo...> - 2007-05-30 15:25:04
|
# HG changeset patch # User Darren Salt <li...@yo...> # Date 1180304657 -3600 # Node ID e99841081777e2bbc405d5e2a81cc37b2f17bd93 # Parent b2645d711337d7a495700259194c3527e94374e3 Initial HTTP auth support (requires xine-lib 1.2, cset 1d942957f51a). This is somewhat insecure: passwords are shown in the clear in the playlist and in saved playlist files, and playlist file access rights are not restricted. diff -r e99841081777e2bbc405d5e2a81cc37b2f17bd93 -r b2645d711337d7a495700259194c3527e94374e3 ChangeLog --- a/ChangeLog Sun May 27 23:24:17 2007 +0100 +++ b/ChangeLog Fri May 25 20:02:57 2007 +0100 @@ -29,6 +29,7 @@ 0.5.900:2007/??/?? * Allow slider widgets to be presented as buttons with pop-up windows. The volume slider in the default windowed-mode toolbar is a pop-up. * Added SPU sync to the A/V window. + * Added support for HTTP authentication. (Requires xine-lib 1.2.) * Obsoleted and disabled most of the deprecated JS functions, except for set_fullscreen() and toolbar_show() which remain deprecated. If you need the others, build with --enable-obsolete. diff -r e99841081777e2bbc405d5e2a81cc37b2f17bd93 -r b2645d711337d7a495700259194c3527e94374e3 src/noskin_window.c --- a/src/noskin_window.c Sun May 27 23:24:17 2007 +0100 +++ b/src/noskin_window.c Fri May 25 20:02:57 2007 +0100 @@ -174,6 +174,9 @@ static gboolean update_slider_cb (gpoint { gint pos_stream, pos_time, length_time; + if (pthread_mutex_trylock (&widgets_update_lock)) + return TRUE; + window_check_vis (FALSE); if (xine_get_status (stream) == XINE_STATUS_PLAY && xine_get_pos_length (stream, &pos_stream, &pos_time, &length_time)) @@ -183,6 +186,7 @@ static gboolean update_slider_cb (gpoint ui_set_status (UI_CURRENT_STATE); } + pthread_mutex_unlock (&widgets_update_lock); return TRUE; } diff -r e99841081777e2bbc405d5e2a81cc37b2f17bd93 -r b2645d711337d7a495700259194c3527e94374e3 src/playlist.c --- a/src/playlist.c Sun May 27 23:24:17 2007 +0100 +++ b/src/playlist.c Fri May 25 20:02:57 2007 +0100 @@ -70,6 +70,12 @@ static GtkToggleButton *repeat_button, * static GtkToggleButton *repeat_button, *random_button, *repeat_track_button; static char logo_mrl[1024]; static int logo_mode; + +static struct { + GtkDialog *dbox; + GtkLabel *label; + GtkEntry *name, *pass; +} auth; static play_item_t *cur_item = NULL; static int cur_list_pos; @@ -1616,6 +1622,97 @@ static void play_next (void) } } +#ifdef XINE_MSG_AUTHENTICATION_NEEDED +static gboolean auth_validate (const char *text) +{ + if (!text || !*text) + return FALSE; + while (*text) + { + unsigned char c = (unsigned char) *text++; + if (c < 33 || c == '/' || c == ':' || c == '@') + return FALSE; + } + return TRUE; +} + +static int display_auth (int args, const char *mrl) +{ + if (GTK_WIDGET_VISIBLE ((GtkWidget *) auth.dbox)) + return 0; + + const char *host = strstr (mrl, "://"); + if (!host) + return 0; + + int retval = 2; + + char *txt; + asprintf (&txt, _("Authorisation required for %s"), mrl); + gtk_window_set_title (GTK_WINDOW (auth.dbox), txt); + free (txt); + gtk_label_set_text (auth.label, args > 1 ? mrl + strlen (mrl) + 1 : ""); + gtk_entry_set_text (auth.name, ""); + gtk_entry_set_text (auth.pass, ""); + + if (gtk_dialog_run (auth.dbox) == GTK_RESPONSE_OK) + { + const char *name = gtk_entry_get_text (auth.name); + const char *pass = gtk_entry_get_text (auth.pass); + if (!auth_validate (name) || !auth_validate (pass)) + { + display_error (FROM_GXINE, "%s", _("Authentication data contains invalid characters.")); + goto ret; + } + + host += 3; + const char *at = strchr (host, '@'); + const char *slash = strchr (host, ':'); + if (at && slash && at > slash) + at = NULL; + if (at) + { + const char *colon = strchr (host, ':'); + if (colon >= at) + at = NULL; + } + + if (at) + asprintf (&txt, "%.*s%s:%s%s", (int)(host - mrl), mrl, name, pass, at); + else + asprintf (&txt, "%.*s%s:%s@%s", (int)(host - mrl), mrl, name, pass, host); + + play_item_t *play_item; + int pos; + for (pos = 0; pos < playlist_size (); ++pos) + if (!strcmp ((play_item = playlist_get_item (pos))->mrl, mrl)) + break; + if (pos == playlist_size ()) + { + pos = playlist_add (play_item_new (NULL, txt, 0, 0), -1); + free (txt); + } + else + { + free (play_item->mrl); + play_item->mrl = txt; + GtkTreeIter iter; + gtk_tree_model_iter_nth_child (pl_model, &iter, NULL, pos); + gtk_list_store_set (pl_store, &iter, COLUMN_MRL, play_item->mrl, -1); + } + playlist_play (pos); + retval = 1; + } + +ret: + gtk_widget_hide ((GtkWidget *) auth.dbox); + gtk_entry_set_text (auth.name, ""); + gtk_entry_set_text (auth.pass, ""); + + return retval; +} +#endif /* XINE_MSG_AUTHENTICATION_NEEDED */ + static void xine_event_cb (void *user_data, const xine_event_t *event) { /* @@ -1793,10 +1890,33 @@ typedef struct { case XINE_MSG_UNKNOWN_DEVICE: msg = display_error; break; + +#ifdef XINE_MSG_AUTHENTICATION_NEEDED + /* new in xine-lib 1.2 */ + case XINE_MSG_AUTHENTICATION_NEEDED: + msg = display_error; + if (data->num_parameters >= 1) + { + play_exec_error_suppress_next (); + switch (display_auth (data->num_parameters, + (const char *)data + data->parameters)) + { + case 2: + puts ("stream stop"); + xine_stop (stream); + case 1: + msg = NULL; + break; + } + } + break; +#endif } /* TODO: provide customized messages, hints... */ - if (data->num_parameters) + if (!msg) + /**/; + else if (data->num_parameters) { int i; const char *param = (char *)data + data->parameters; @@ -2388,6 +2508,35 @@ void playlist_init (void) check_list_empty (); /* + * authorisation dbox + */ + + auth.dbox = GTK_DIALOG (gtk_dialog_new_with_buttons + ("", (GtkWindow *) app, + GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR, + GTK_STOCK_CANCEL, GTK_RESPONSE_DELETE_EVENT, + GTK_STOCK_OPEN, GTK_RESPONSE_OK, + NULL)); + auth.label = GTK_LABEL (gtk_label_new ("")); + auth.name = GTK_ENTRY (gtk_entry_new_with_max_length (64)); + auth.pass = GTK_ENTRY (gtk_entry_new_with_max_length (128)); + gtk_entry_set_visibility (GTK_ENTRY (auth.pass), FALSE); + GtkWidget *table = gtk_table_new (2, 2, FALSE); + add_table_row_items (table, 0, 1, _("User name"), auth.name, NULL); + add_table_row_items (table, 1, 1, _("Password"), auth.pass, NULL); + vbox = GTK_BOX (gtk_hbox_new (0, 2)); + gtk_box_pack_start (vbox, + gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION, + GTK_ICON_SIZE_DIALOG), + FALSE, FALSE, 0); + gtk_box_pack_start (vbox, table, TRUE, TRUE, 0); + gtk_box_pack_start ((GtkBox *) auth.dbox->vbox, (GtkWidget *) auth.label, + TRUE, TRUE, 0); + gtk_box_pack_start ((GtkBox *) auth.dbox->vbox, (GtkWidget *) vbox, + TRUE, TRUE, 0); + gtk_widget_show_all ((GtkWidget *) vbox); + + /* * event handling */ xine_event_create_listener_thread (xine_event_new_queue (stream), |