diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 81 | ||||
-rw-r--r-- | src/caja-share-bar.c | 215 | ||||
-rw-r--r-- | src/caja-share-bar.h | 61 | ||||
-rw-r--r-- | src/file-share-properties.c | 688 | ||||
-rw-r--r-- | src/http.c | 481 | ||||
-rw-r--r-- | src/http.h | 27 | ||||
-rw-r--r-- | src/marshal.list | 1 | ||||
-rw-r--r-- | src/obexftp.c | 162 | ||||
-rw-r--r-- | src/obexftp.h | 29 | ||||
-rw-r--r-- | src/obexpush.c | 563 | ||||
-rw-r--r-- | src/obexpush.h | 32 | ||||
-rw-r--r-- | src/share-extension.c | 299 | ||||
-rw-r--r-- | src/user_share-common.c | 89 | ||||
-rw-r--r-- | src/user_share-common.h | 30 | ||||
-rw-r--r-- | src/user_share-private.c | 102 | ||||
-rw-r--r-- | src/user_share-private.h | 57 | ||||
-rw-r--r-- | src/user_share.c | 572 | ||||
-rw-r--r-- | src/user_share.h | 25 |
18 files changed, 3514 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..90be13d --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,81 @@ + +MARSHALFILES = marshal.c marshal.h +BUILT_SOURCES = $(MARSHALFILES) + +marshal.c: marshal.h + $(AM_V_GEN) ( $(GLIB_GENMARSHAL) --prefix=marshal $(srcdir)/marshal.list --header --body > marshal.c ) +marshal.h: marshal.list + $(AM_V_GEN) ( $(GLIB_GENMARSHAL) --prefix=marshal $(srcdir)/marshal.list --header > marshal.h ) + + +bin_PROGRAMS= \ + mate-file-share-properties + +libexec_PROGRAMS= \ + mate-user-share + +noinst_LTLIBRARIES = libuser-share-common.la +libuser_share_common_la_SOURCES = user_share-common.c user_share-common.h + +INCLUDES= \ + -DPREFIX=\""$(prefix)"\" \ + -DBINDIR=\""$(bindir)"\" \ + -DLIBEXECDIR=\""$(libexecdir)"\" \ + -DUSER_SHARE_PROGRAM=\""$(libexecdir)/mate-user-share"\" \ + -DMATELOCALEDIR=\""$(datadir)/locale"\" \ + -DDATADIR=\""$(datadir)/mate-user-share/"\" \ + -DHTTPD_CONFIG_TEMPLATE=\""$(datadir)/mate-user-share/dav_user_%s.conf"\" \ + -DHTTPD_PROGRAM=\""$(HTTPD)"\" \ + -DHTTPD_MODULES_PATH=\""$(MODULES_PATH)"\" \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + $(EXTENSION_CFLAGS) \ + $(USER_SHARE_CFLAGS) \ + $(USER_SHARE_CONFIG_CFLAGS) \ + $(X_CFLAGS) + +mate_user_share_SOURCES = \ + user_share.c \ + user_share.h \ + user_share-private.h \ + user_share-private.c \ + http.c \ + http.h \ + obexftp.c \ + obexftp.h \ + obexpush.c \ + obexpush.h \ + $(MARSHALFILES) + +mate_user_share_LDADD = \ + libuser-share-common.la \ + $(USER_SHARE_LIBS) \ + $(SELINUX_LIBS) \ + $(X_LIBS) $(X_PRE_LIBS) -lX11 $(X_EXTRA_LIBS) + +mate_file_share_properties_SOURCES = \ + file-share-properties.c \ + user_share-private.h \ + user_share-private.c + +mate_file_share_properties_LDADD = \ + $(USER_SHARE_CONFIG_LIBS) + +caja_extensiondir = $(CAJADIR) +caja_extension_LTLIBRARIES = libcaja-share-extension.la + +libcaja_share_extension_la_SOURCES = \ + caja-share-bar.c \ + caja-share-bar.h \ + share-extension.c \ + $(NULL) + +libcaja_share_extension_la_LIBADD = libuser-share-common.la $(EXTENSION_LIBS) +libcaja_share_extension_la_LDFLAGS = -avoid-version -module -no-undefined + +EXTRA_DIST = marshal.list + +CLEANFILES = $(BUILT_SOURCES) + + +-include $(top_srcdir)/git.mk diff --git a/src/caja-share-bar.c b/src/caja-share-bar.c new file mode 100644 index 0000000..8741ac4 --- /dev/null +++ b/src/caja-share-bar.c @@ -0,0 +1,215 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2005 William Jon McCann <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Authors: William Jon McCann <[email protected]> + * + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> +#include <gtk/gtk.h> + +#include "caja-share-bar.h" + +static void caja_share_bar_finalize (GObject *object); + +#define CAJA_SHARE_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CAJA_TYPE_SHARE_BAR, CajaShareBarPrivate)) + +struct CajaShareBarPrivate +{ + GtkWidget *button; + GtkWidget *label; + char *str; +}; + +enum { + PROP_0, + PROP_LABEL +}; + +enum { + ACTIVATE, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = { 0, }; + +G_DEFINE_TYPE (CajaShareBar, caja_share_bar, GTK_TYPE_HBOX) + +GtkWidget * +caja_share_bar_get_button (CajaShareBar *bar) +{ + GtkWidget *button; + + g_return_val_if_fail (bar != NULL, NULL); + + button = bar->priv->button; + + return button; +} + +static void +caja_share_bar_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + CajaShareBar *self; + + self = CAJA_SHARE_BAR (object); + + switch (prop_id) { + case PROP_LABEL: { + char *str; + g_free (self->priv->str); + str = g_strdup_printf ("<i>%s</i>", g_value_get_string (value)); + gtk_label_set_markup (GTK_LABEL (self->priv->label), str); + self->priv->str = g_value_dup_string (value); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +caja_share_bar_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + CajaShareBar *self; + + self = CAJA_SHARE_BAR (object); + + switch (prop_id) { + case PROP_LABEL: + g_value_set_string (value, self->priv->str); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +caja_share_bar_class_init (CajaShareBarClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = caja_share_bar_finalize; + object_class->get_property = caja_share_bar_get_property; + object_class->set_property = caja_share_bar_set_property; + + g_type_class_add_private (klass, sizeof (CajaShareBarPrivate)); + + g_object_class_install_property (G_OBJECT_CLASS(klass), + PROP_LABEL, g_param_spec_string ("label", + "label", "The widget's main label", NULL, G_PARAM_READWRITE)); + + + signals [ACTIVATE] = g_signal_new ("activate", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CajaShareBarClass, activate), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + +} + +static void +button_clicked_cb (GtkWidget *button, + CajaShareBar *bar) +{ + g_signal_emit (bar, signals [ACTIVATE], 0); +} + +static void +caja_share_bar_init (CajaShareBar *bar) +{ + GtkWidget *label; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *image; + char *hint; + + bar->priv = CAJA_SHARE_BAR_GET_PRIVATE (bar); + + hbox = GTK_WIDGET (bar); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + label = gtk_label_new (_("Personal File Sharing")); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); + + bar->priv->label = gtk_label_new (""); + hint = g_strdup_printf ("<i>%s</i>", ""); + gtk_label_set_markup (GTK_LABEL (bar->priv->label), hint); + gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0.0, 0.5); + gtk_widget_show (bar->priv->label); + gtk_box_pack_start (GTK_BOX (vbox), bar->priv->label, TRUE, TRUE, 0); + + bar->priv->button = gtk_button_new_with_label (_("Launch Preferences")); + gtk_widget_show (bar->priv->button); + gtk_box_pack_end (GTK_BOX (hbox), bar->priv->button, FALSE, FALSE, 0); + + image = gtk_image_new_from_icon_name ("folder-remote", GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image); + gtk_button_set_image (GTK_BUTTON (bar->priv->button), image); + + g_signal_connect (bar->priv->button, "clicked", + G_CALLBACK (button_clicked_cb), + bar); + + gtk_widget_set_tooltip_text (bar->priv->button, + _("Launch Personal File Sharing Preferences")); +} + +static void +caja_share_bar_finalize (GObject *object) +{ + CajaShareBar *bar; + + g_return_if_fail (object != NULL); + g_return_if_fail (CAJA_IS_SHARE_BAR (object)); + + bar = CAJA_SHARE_BAR (object); + + g_return_if_fail (bar->priv != NULL); + + G_OBJECT_CLASS (caja_share_bar_parent_class)->finalize (object); +} + +GtkWidget * +caja_share_bar_new (const char *label) +{ + GObject *result; + + result = g_object_new (CAJA_TYPE_SHARE_BAR, + "label", label, + NULL); + + return GTK_WIDGET (result); +} diff --git a/src/caja-share-bar.h b/src/caja-share-bar.h new file mode 100644 index 0000000..0d3df12 --- /dev/null +++ b/src/caja-share-bar.h @@ -0,0 +1,61 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2005 William Jon McCann <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Authors: William Jon McCann <[email protected]> + * + */ + +#ifndef __CAJA_SHARE_BAR_H +#define __CAJA_SHARE_BAR_H + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define CAJA_TYPE_SHARE_BAR (caja_share_bar_get_type ()) +#define CAJA_SHARE_BAR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CAJA_TYPE_SHARE_BAR, CajaShareBar)) +#define CAJA_SHARE_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CAJA_TYPE_SHARE_BAR, CajaShareBarClass)) +#define CAJA_IS_SHARE_BAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CAJA_TYPE_SHARE_BAR)) +#define CAJA_IS_SHARE_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CAJA_TYPE_SHARE_BAR)) +#define CAJA_SHARE_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CAJA_TYPE_SHARE_BAR, CajaShareBarClass)) + +typedef struct CajaShareBarPrivate CajaShareBarPrivate; + +typedef struct +{ + GtkHBox box; + + CajaShareBarPrivate *priv; +} CajaShareBar; + +typedef struct +{ + GtkHBoxClass parent_class; + + void (* activate) (CajaShareBar *bar); + +} CajaShareBarClass; + +GType caja_share_bar_get_type (void); +GtkWidget *caja_share_bar_new (const char *label); + +GtkWidget *caja_share_bar_get_button (CajaShareBar *bar); + +G_END_DECLS + +#endif /* __GS_SHARE_BAR_H */ diff --git a/src/file-share-properties.c b/src/file-share-properties.c new file mode 100644 index 0000000..d46958f --- /dev/null +++ b/src/file-share-properties.c @@ -0,0 +1,688 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ + +/* + * Copyright (C) 2004 Red Hat, Inc. + * + * Caja is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Caja is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Alexander Larsson <[email protected]> + * + */ + +#include "config.h" + +#include <string.h> +#include <stdio.h> + +#include <gtk/gtk.h> +#include <glib/gi18n.h> +#include <mateconf/mateconf-client.h> +#include <unique/uniqueapp.h> + +#include "user_share-private.h" + +#define REALM "Please log in as the user guest" +#define USER "guest" + +static GtkBuilder* builder; + + +static void +write_out_password (const char *password) +{ + char *to_hash; + char *ascii_digest; + char *line; + char *filename; + FILE *file; + + to_hash = g_strdup_printf ("%s:%s:%s", USER, REALM, password); + ascii_digest = g_compute_checksum_for_string (G_CHECKSUM_MD5, to_hash, strlen (to_hash)); + g_free (to_hash); + line = g_strdup_printf ("%s:%s:%s\n", USER, REALM, ascii_digest); + g_free (ascii_digest); + + filename = g_build_filename (g_get_user_config_dir (), "user-share", "passwd", NULL); + + file = fopen (filename, "w"); + if (file != NULL) { + fwrite (line, strlen (line), 1, file); + fclose (file); + } + + g_free (filename); + g_free (line); +} + +static void +flush_password (void) +{ + GtkWidget *password_entry; + const char *password; + + password_entry = GTK_WIDGET (gtk_builder_get_object (builder, "password_entry")); + + if (g_object_get_data (G_OBJECT( password_entry), "user_edited")) { + password = gtk_entry_get_text (GTK_ENTRY (password_entry)); + if (password != NULL && password[0] != 0) + write_out_password (password); + } +} + + +static void +update_ui (void) +{ + MateConfClient *client; + gboolean enabled, bluetooth_enabled, bluetooth_write_enabled, require_pairing_enabled; + gboolean bluetooth_obexpush_enabled, bluetooth_obexpush_notify; + char *str; + PasswordSetting password_setting; + AcceptSetting accept_setting; + GtkWidget *check; + GtkWidget *password_combo; + GtkWidget *password_entry; + GtkWidget *bluetooth_check; + GtkWidget *allow_write_bluetooth_check; + GtkWidget *require_pairing_check; + GtkWidget *enable_obexpush_check; + GtkWidget *accept_obexpush_combo; + GtkWidget *notify_received_obexpush_check; + + client = mateconf_client_get_default (); + + enabled = mateconf_client_get_bool (client, + FILE_SHARING_ENABLED, + NULL); + bluetooth_enabled = mateconf_client_get_bool (client, + FILE_SHARING_BLUETOOTH_ENABLED, + NULL); + bluetooth_write_enabled = mateconf_client_get_bool (client, + FILE_SHARING_BLUETOOTH_ALLOW_WRITE, + NULL); + require_pairing_enabled = mateconf_client_get_bool (client, + FILE_SHARING_BLUETOOTH_REQUIRE_PAIRING, + NULL); + bluetooth_obexpush_enabled = mateconf_client_get_bool (client, + FILE_SHARING_BLUETOOTH_OBEXPUSH_ENABLED, + NULL); + bluetooth_obexpush_notify = mateconf_client_get_bool (client, + FILE_SHARING_BLUETOOTH_OBEXPUSH_NOTIFY, + NULL); + + str = mateconf_client_get_string (client, FILE_SHARING_REQUIRE_PASSWORD, NULL); + password_setting = password_setting_from_string (str); + g_free (str); + + str = mateconf_client_get_string (client, FILE_SHARING_BLUETOOTH_OBEXPUSH_ACCEPT_FILES, NULL); + accept_setting = accept_setting_from_string (str); + g_free (str); + + check = GTK_WIDGET (gtk_builder_get_object (builder, "enable_check")); + password_combo = GTK_WIDGET (gtk_builder_get_object (builder, "password_combo")); + password_entry = GTK_WIDGET (gtk_builder_get_object (builder, "password_entry")); + bluetooth_check = GTK_WIDGET (gtk_builder_get_object (builder, "enable_bluetooth_check")); + allow_write_bluetooth_check = GTK_WIDGET (gtk_builder_get_object (builder, "allow_write_bluetooth_check")); + require_pairing_check = GTK_WIDGET (gtk_builder_get_object (builder, "require_pairing_check")); + enable_obexpush_check = GTK_WIDGET (gtk_builder_get_object (builder, "enable_obexpush_check")); + accept_obexpush_combo = GTK_WIDGET (gtk_builder_get_object (builder, "accept_obexpush_combo")); + notify_received_obexpush_check = GTK_WIDGET (gtk_builder_get_object (builder, "notify_received_obexpush_check")); + + /* Network */ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), enabled); + gtk_widget_set_sensitive (password_combo, enabled); + gtk_widget_set_sensitive (password_entry, enabled && password_setting != PASSWORD_NEVER); + + gtk_combo_box_set_active (GTK_COMBO_BOX (password_combo), + password_setting); + + /* Bluetooth ObexFTP */ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bluetooth_check), bluetooth_enabled); + gtk_widget_set_sensitive (allow_write_bluetooth_check, bluetooth_enabled); + gtk_widget_set_sensitive (require_pairing_check, bluetooth_enabled); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (allow_write_bluetooth_check), + bluetooth_write_enabled); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (require_pairing_check), + require_pairing_enabled); + + /* Bluetooth ObexPush */ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (enable_obexpush_check), bluetooth_obexpush_enabled); + gtk_widget_set_sensitive (accept_obexpush_combo, bluetooth_obexpush_enabled); + gtk_widget_set_sensitive (notify_received_obexpush_check, bluetooth_obexpush_enabled); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (notify_received_obexpush_check), + bluetooth_obexpush_notify); + + gtk_combo_box_set_active (GTK_COMBO_BOX (accept_obexpush_combo), + accept_setting); + + g_object_unref (client); +} + +static void +file_sharing_enabled_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + update_ui (); +} + +static void +password_required_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + update_ui (); +} + +static void +file_sharing_bluetooth_enabled_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + update_ui (); +} + +static void +file_sharing_bluetooth_allow_write_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + update_ui (); +} + +static void +file_sharing_bluetooth_require_pairing_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + update_ui (); +} + +static void +file_sharing_bluetooth_obexpush_enabled_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + update_ui (); +} + +static void +file_sharing_bluetooth_obexpush_accept_files_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + update_ui (); +} + +static void +file_sharing_bluetooth_obexpush_notify_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + update_ui (); +} + +static void +password_combo_changed (GtkComboBox *combo_box) +{ + MateConfClient *client; + guint setting; + + setting = gtk_combo_box_get_active (combo_box); + + client = mateconf_client_get_default (); + + mateconf_client_set_string (client, + FILE_SHARING_REQUIRE_PASSWORD, + password_string_from_setting (setting), + NULL); + g_object_unref (client); +} + +static void +launch_share (void) +{ + char *argv[2]; + int i; + + i = 0; + argv[i++] = USER_SHARE_PROGRAM; + argv[i++] = NULL; + + if (!g_spawn_async (NULL, + argv, + NULL, + 0, /* G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL */ + NULL, + NULL, + NULL, + NULL)) { + g_warning ("Unable to start mate-user-share program"); + } +} + +static void +enable_bluetooth_check_toggled (GtkWidget *check) +{ + MateConfClient *client; + gboolean enabled; + + enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)); + + client = mateconf_client_get_default (); + + mateconf_client_set_bool (client, + FILE_SHARING_BLUETOOTH_ENABLED, + enabled, + NULL); + + g_object_unref (client); + + if (enabled != FALSE) + launch_share (); +} + +static void +enable_check_toggled (GtkWidget *check) +{ + MateConfClient *client; + gboolean enabled; + + enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)); + + client = mateconf_client_get_default (); + + mateconf_client_set_bool (client, + FILE_SHARING_ENABLED, + enabled, + NULL); + + g_object_unref (client); + + if (enabled != FALSE) + launch_share (); +} + +static void +password_entry_changed (GtkEditable *editable) +{ + g_object_set_data (G_OBJECT (editable), + "user_edited", GINT_TO_POINTER (1)); + flush_password (); +} + +static void +bluetooth_allow_write_check_toggled (GtkWidget *check) +{ + MateConfClient *client; + gboolean enabled; + + enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)); + + client = mateconf_client_get_default (); + + mateconf_client_set_bool (client, + FILE_SHARING_BLUETOOTH_ALLOW_WRITE, + enabled, + NULL); + + g_object_unref (client); +} + +static void +bluetooth_require_pairing_check_toggled (GtkWidget *check) +{ + MateConfClient *client; + gboolean enabled; + + enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)); + + client = mateconf_client_get_default (); + + mateconf_client_set_bool (client, + FILE_SHARING_BLUETOOTH_REQUIRE_PAIRING, + enabled, + NULL); + + g_object_unref (client); +} + +static void +enable_obexpush_check_toggled (GtkWidget *check) +{ + MateConfClient *client; + gboolean enabled; + + enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)); + + client = mateconf_client_get_default (); + + mateconf_client_set_bool (client, + FILE_SHARING_BLUETOOTH_OBEXPUSH_ENABLED, + enabled, + NULL); + + g_object_unref (client); + + if (enabled != FALSE) + launch_share (); +} + +static void +accept_obexpush_combo_changed (GtkComboBox *combo_box) +{ + MateConfClient *client; + guint setting; + + setting = gtk_combo_box_get_active (combo_box); + + client = mateconf_client_get_default (); + + mateconf_client_set_string (client, + FILE_SHARING_BLUETOOTH_OBEXPUSH_ACCEPT_FILES, + accept_string_from_setting (setting), + NULL); + g_object_unref (client); +} + +static void +notify_received_obexpush_check_toggled (GtkWidget *check) +{ + MateConfClient *client; + gboolean enabled; + + enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)); + + client = mateconf_client_get_default (); + + mateconf_client_set_bool (client, + FILE_SHARING_BLUETOOTH_OBEXPUSH_NOTIFY, + enabled, + NULL); + + g_object_unref (client); +} + +static GtkWidget * +error_dialog (const char *title, + const char *reason, + GtkWindow *parent) +{ + GtkWidget *error_dialog; + + if (reason == NULL) + reason = _("No reason"); + + error_dialog = + gtk_message_dialog_new (parent, + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + "%s", title); + gtk_message_dialog_format_secondary_text + (GTK_MESSAGE_DIALOG (error_dialog), "%s", reason); + + gtk_window_set_title (GTK_WINDOW (error_dialog), ""); /* as per HIG */ + gtk_container_set_border_width (GTK_CONTAINER (error_dialog), 5); + gtk_dialog_set_default_response (GTK_DIALOG (error_dialog), + GTK_RESPONSE_OK); + gtk_window_set_modal (GTK_WINDOW (error_dialog), TRUE); + + return error_dialog; +} + +static void +help_button_clicked (GtkButton *button, GtkWidget *window) +{ + GError *error = NULL; + + if (gtk_show_uri (gtk_widget_get_screen (window), "ghelp:mate-user-share", gtk_get_current_event_time (), &error) == FALSE) { + GtkWidget *dialog; + + dialog = error_dialog (_("Could not display the help contents."), error->message, GTK_WINDOW (window)); + g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK + (gtk_widget_destroy), error_dialog); + gtk_window_present (GTK_WINDOW (dialog)); + + g_error_free (error); + } +} + +static UniqueResponse +message_received_cb (UniqueApp *app, + int command, + UniqueMessageData *message_data, + guint time_, + gpointer user_data) +{ + gtk_window_present (GTK_WINDOW (user_data)); + + return UNIQUE_RESPONSE_OK; +} + +int +main (int argc, char *argv[]) +{ + GError *error = NULL; + MateConfClient *client; + GtkWidget *check; + GtkWidget *password_combo; + GtkWidget *password_entry; + GtkWidget *bluetooth_check; + GtkWidget *bluetooth_allow_write_check; + GtkWidget *require_pairing_check; + GtkWidget *enable_obexpush_check; + GtkWidget *accept_obexpush_combo; + GtkWidget *notify_received_obexpush_check; + GtkWidget *window; + GtkListStore *store; + GtkCellRenderer *cell; + GtkTreeIter iter; + UniqueApp *app; + + bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + gtk_init (&argc, &argv); + + app = unique_app_new ("org.mate.user-share.properties", NULL); + if (unique_app_is_running (app)) { + gdk_notify_startup_complete (); + unique_app_send_message (app, UNIQUE_ACTIVATE, NULL); + return 0; + } + + builder = gtk_builder_new (); + gtk_builder_add_from_file (builder, DATADIR"file-share-properties.ui", &error); + + if (error) { + GtkWidget *dialog; + + dialog = error_dialog (_("Could not build interface."), error->message, NULL); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + g_error_free (error); + return 1; + } + + window = GTK_WIDGET (gtk_builder_get_object (builder, "user_share_dialog")); + g_signal_connect (G_OBJECT (window), "delete_event", + G_CALLBACK (gtk_main_quit), NULL); + g_signal_connect (app, "message-received", + G_CALLBACK (message_received_cb), window); + + client = mateconf_client_get_default (); + mateconf_client_add_dir (client, + FILE_SHARING_DIR, + MATECONF_CLIENT_PRELOAD_RECURSIVE, + NULL); + + check = GTK_WIDGET (gtk_builder_get_object (builder, "enable_check")); + password_combo = GTK_WIDGET (gtk_builder_get_object (builder, "password_combo")); + password_entry = GTK_WIDGET (gtk_builder_get_object (builder, "password_entry")); + bluetooth_check = GTK_WIDGET (gtk_builder_get_object (builder, "enable_bluetooth_check")); + bluetooth_allow_write_check = GTK_WIDGET (gtk_builder_get_object (builder, "allow_write_bluetooth_check")); + require_pairing_check = GTK_WIDGET (gtk_builder_get_object (builder, "require_pairing_check")); + enable_obexpush_check = GTK_WIDGET (gtk_builder_get_object (builder, "enable_obexpush_check")); + accept_obexpush_combo = GTK_WIDGET (gtk_builder_get_object (builder, "accept_obexpush_combo")); + notify_received_obexpush_check = GTK_WIDGET (gtk_builder_get_object (builder, "notify_received_obexpush_check")); + + store = gtk_list_store_new (1, G_TYPE_STRING); + gtk_combo_box_set_model (GTK_COMBO_BOX (password_combo), + GTK_TREE_MODEL (store)); + cell = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (password_combo), cell, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (password_combo), cell, + "text", 0, + NULL); + + /* Keep in same order as enum */ + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, + _("Never"), -1); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, + _("When writing files"), -1); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, + _("Always"), -1); + g_object_unref (store); + + /* We can't read the password from the text, just set it to something */ + gtk_entry_set_text (GTK_ENTRY (password_entry), "none"); + g_object_set_data (G_OBJECT (password_entry), + "user_edited", GINT_TO_POINTER (0)); + g_signal_connect (password_entry, + "changed", G_CALLBACK (password_entry_changed), NULL); + + /* Accept files combo */ + store = gtk_list_store_new (1, G_TYPE_STRING); + gtk_combo_box_set_model (GTK_COMBO_BOX (accept_obexpush_combo), + GTK_TREE_MODEL (store)); + cell = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (accept_obexpush_combo), cell, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (accept_obexpush_combo), cell, + "text", 0, + NULL); + + /* Keep in same order as enum */ + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, + _("Always"), -1); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, + _("Only for set up devices"), -1); + //FIXME implement +#if 0 + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, + _("Ask"), -1); +#endif + g_object_unref (store); + + update_ui (); + + g_signal_connect (check, + "toggled", G_CALLBACK (enable_check_toggled), NULL); + g_signal_connect (password_combo, + "changed", G_CALLBACK (password_combo_changed), NULL); + g_signal_connect (bluetooth_check, + "toggled", G_CALLBACK (enable_bluetooth_check_toggled), NULL); + g_signal_connect (bluetooth_allow_write_check, + "toggled", G_CALLBACK (bluetooth_allow_write_check_toggled), NULL); + g_signal_connect (require_pairing_check, + "toggled", G_CALLBACK (bluetooth_require_pairing_check_toggled), NULL); + g_signal_connect (enable_obexpush_check, + "toggled", G_CALLBACK (enable_obexpush_check_toggled), NULL); + g_signal_connect (accept_obexpush_combo, + "changed", G_CALLBACK (accept_obexpush_combo_changed), NULL); + g_signal_connect (notify_received_obexpush_check, + "toggled", G_CALLBACK (notify_received_obexpush_check_toggled), NULL); + + g_signal_connect (GTK_WIDGET (gtk_builder_get_object (builder, "close_button")), + "clicked", G_CALLBACK (gtk_main_quit), NULL); + g_signal_connect (GTK_WIDGET (gtk_builder_get_object (builder, "help_button")), + "clicked", G_CALLBACK (help_button_clicked), + gtk_builder_get_object (builder, "user_share_dialog")); + + mateconf_client_notify_add (client, + FILE_SHARING_ENABLED, + file_sharing_enabled_changed, + NULL, + NULL, + NULL); + mateconf_client_notify_add (client, + FILE_SHARING_REQUIRE_PASSWORD, + password_required_changed, + NULL, + NULL, + NULL); + mateconf_client_notify_add (client, + FILE_SHARING_BLUETOOTH_ENABLED, + file_sharing_bluetooth_enabled_changed, + NULL, + NULL, + NULL); + mateconf_client_notify_add (client, + FILE_SHARING_BLUETOOTH_ALLOW_WRITE, + file_sharing_bluetooth_allow_write_changed, + NULL, + NULL, + NULL); + mateconf_client_notify_add (client, + FILE_SHARING_BLUETOOTH_REQUIRE_PAIRING, + file_sharing_bluetooth_require_pairing_changed, + NULL, + NULL, + NULL); + mateconf_client_notify_add (client, + FILE_SHARING_BLUETOOTH_OBEXPUSH_ENABLED, + file_sharing_bluetooth_obexpush_enabled_changed, + NULL, + NULL, + NULL); + mateconf_client_notify_add (client, + FILE_SHARING_BLUETOOTH_OBEXPUSH_ACCEPT_FILES, + file_sharing_bluetooth_obexpush_accept_files_changed, + NULL, + NULL, + NULL); + mateconf_client_notify_add (client, + FILE_SHARING_BLUETOOTH_OBEXPUSH_NOTIFY, + file_sharing_bluetooth_obexpush_notify_changed, + NULL, + NULL, + NULL); + + g_object_unref (client); + + gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (builder, "user_share_dialog"))); + + gtk_main (); + + return 0; +} diff --git a/src/http.c b/src/http.c new file mode 100644 index 0000000..64d4706 --- /dev/null +++ b/src/http.c @@ -0,0 +1,481 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ + +/* + * Copyright (C) 2004-2008 Red Hat, Inc. + * + * Caja is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Caja is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Alexander Larsson <[email protected]> + * + */ + +#include "config.h" + +#include <glib.h> +#include <glib/gi18n.h> +#include <X11/Xlib.h> + +#ifdef HAVE_DBUS_1_1 +#include <dbus/dbus.h> +#endif + +#include <mateconf/mateconf-client.h> + +#include <stdarg.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/stat.h> + +#ifdef HAVE_SELINUX +#include <selinux/selinux.h> +#endif + +#include "user_share-common.h" +#include "user_share-private.h" +#include "http.h" + +/* From avahi-common/domain.h */ +#define AVAHI_LABEL_MAX 64 + +#ifdef HAVE_DBUS_1_1 +static char *dbus_session_id; +#endif + +static pid_t httpd_pid = 0; + +static int +get_port (void) +{ + int sock; + struct sockaddr_in addr; + int reuse; + socklen_t len; + + sock = socket (PF_INET, SOCK_STREAM, 0); + if (sock < 0) { + return -1; + } + + memset (&addr, 0, sizeof (addr)); + addr.sin_port = 0; + addr.sin_addr.s_addr = INADDR_ANY; + + reuse = 1; + setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof (reuse)); + if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) == -1) { + close (sock); + return -1; + } + + len = sizeof (addr); + if (getsockname (sock, (struct sockaddr *)&addr, &len) == -1) { + close (sock); + return -1; + } + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) + /* XXX This exposes a potential race condition, but without this, + * httpd will not start on the above listed platforms due to the fact + * that SO_REUSEADDR is also needed when Apache binds to the listening + * socket. At this time, Apache does not support that socket option. + */ + close (sock); +#endif + return ntohs (addr.sin_port); +} + +static char * +truncate_name (const char *name) +{ + const char *end; + + end = g_utf8_find_prev_char (name, name + 64); + g_assert (end != NULL); + return g_strndup (name, end - name); +} + +static char * +get_share_name (void) +{ + static char *name = NULL; + const char *host_name; + char *str; + + if (name == NULL) { + host_name = g_get_host_name (); + if (strcmp (host_name, "localhost") == 0) { + /* Translators: The %s will get filled in with the user name + of the user, to form a genitive. If this is difficult to + translate correctly so that it will work correctly in your + language, you may use something equivalent to + "Public files of %s", or leave out the %s altogether. + In the latter case, please put "%.0s" somewhere in the string, + which will match the user name string passed by the C code, + but not put the user name in the final string. This is to + avoid the warning that msgfmt might otherwise generate. */ + name = g_strdup_printf (_("%s's public files"), g_get_user_name ()); + } else { + /* Translators: This is similar to the string before, only it + has the hostname in it too. */ + name = g_strdup_printf (_("%s's public files on %s"), + g_get_user_name (), + host_name); + } + + } + /* And truncate */ + if (strlen (name) < AVAHI_LABEL_MAX) + return name; + + str = truncate_name (name); + g_free (name); + name = str; + + return name; +} + +#ifdef HAVE_DBUS_1_1 +static void +init_dbus() { + /* The only use we make of D-BUS is to fetch the session BUS ID so we can export + * it via mDNS, so we connect and then immediately disconnect. If we were using + * the D-BUS session BUS for something persistent, the following code should use + * dbus_bus_get() and skip the shutdown. (Avahi uses the D-BUS _system_ bus + * internally.) + */ + + DBusError derror; + DBusConnection *connection; + + dbus_error_init(&derror); + + connection = dbus_bus_get_private(DBUS_BUS_SESSION, &derror); + if (connection == NULL) { + g_printerr("Failed to connect to session bus: %s", derror.message); + dbus_error_free(&derror); + return; + } + + dbus_session_id = dbus_bus_get_id(connection, &derror); + if (dbus_session_id == NULL) { + /* This can happen if the D-BUS library has been upgraded to 1.1, but the + * user's session hasn't yet been restarted + */ + g_printerr("Failed to get session BUS ID: %s", derror.message); + dbus_error_free(&derror); + } + + dbus_connection_set_exit_on_disconnect(connection, FALSE); + dbus_connection_close(connection); + dbus_connection_unref(connection); +} +#endif + +static void +ensure_conf_dir (void) +{ + char *dirname; + + dirname = g_build_filename (g_get_user_config_dir (), "user-share", NULL); + g_mkdir_with_parents (dirname, 0755); + g_free (dirname); +} + +static void +httpd_child_setup (gpointer user_data) +{ +#ifdef HAVE_SELINUX + char *mycon; + /* If selinux is enabled, avoid transitioning to the httpd_t context, + as this normally means you can't read the users homedir. */ + if (is_selinux_enabled()) { + if (getcon (&mycon) < 0) { + abort (); + } + if (setexeccon (mycon) < 0) + abort (); + freecon (mycon); + } +#endif +} + +static const char *known_httpd_locations [] = { + HTTPD_PROGRAM, + "/usr/sbin/httpd", + "/usr/sbin/httpd2", + "/usr/sbin/apache2", + NULL +}; + +static char* +get_httpd_program () +{ + int i; + + for (i = 0; known_httpd_locations[i]; i++) { + if (known_httpd_locations[i][0] == '\0') { + /* empty string as first element, happens when + * configured --with-httpd=auto */ + continue; + } + if (g_file_test (known_httpd_locations[i], G_FILE_TEST_IS_EXECUTABLE) + && ! g_file_test (known_httpd_locations[i], G_FILE_TEST_IS_DIR)) { + return g_strdup (known_httpd_locations[i]); + } + } + return NULL; +} + +static const char *known_httpd_modules_locations [] = { + HTTPD_MODULES_PATH, + "/etc/httpd/modules", + "/usr/lib/apache2/modules", + NULL +}; + +static gchar* +get_httpd_modules_path () +{ + int i; + + for (i = 0; known_httpd_modules_locations[i]; i++) { + if (known_httpd_modules_locations[i][0] == '\0') { + /* empty string as first element, happens when + * configured --with-httpd=auto */ + continue; + } + if (g_file_test (known_httpd_modules_locations[i], G_FILE_TEST_IS_EXECUTABLE) + && g_file_test (known_httpd_modules_locations[i], G_FILE_TEST_IS_DIR)) { + return g_strdup (known_httpd_modules_locations[i]); + } + } + return NULL; +} + +static GRegex *version_regex = NULL; + +static char* +get_httpd_config (const char *httpd_program) +{ + gchar *standard_output; + gchar *cmd_line; + GMatchInfo *match_info; + gchar *version_number = NULL; + gchar *config; + + cmd_line = g_strdup_printf ("%s -v", httpd_program); + if (! g_spawn_command_line_sync (cmd_line, &standard_output, NULL, NULL, NULL)) { + g_free (cmd_line); + return NULL; + } + g_free (cmd_line); + + if (version_regex == NULL) { + version_regex = g_regex_new ("\\d\\.\\d", 0, 0, NULL); + } + + if (g_regex_match (version_regex, standard_output, 0, &match_info)) { + while (g_match_info_matches (match_info)) { + version_number = g_match_info_fetch (match_info, 0); + break; + } + g_match_info_free (match_info); + g_free (standard_output); + } else { + /* Failed to parse httpd version number */ + g_warning ("Could not parse '%s' as a version for httpd", standard_output); + g_free (standard_output); + /* assume it is 2.2 */ + version_number = g_strdup ("2.2"); + } + + config = g_strdup_printf (HTTPD_CONFIG_TEMPLATE, version_number); + g_free (version_number); + + return config; +} + +static gboolean +spawn_httpd (int port, pid_t *pid_out) +{ + char *free1, *free2, *free3, *free4, *free5, *free6, *free7, *free8, *free9; + gboolean res; + char *argv[10]; + char *env[10]; + int i; + gint status; + char *pid_filename; + char *pidfile; + GError *error; + gboolean got_pidfile; + MateConfClient *client; + char *str; + char *public_dir; + + public_dir = lookup_public_dir (); + ensure_conf_dir (); + + i = 0; + free1 = argv[i++] = get_httpd_program (); + if (argv[0] == NULL) { + fprintf (stderr, "error finding httpd server\n"); + return FALSE; + } + + argv[i++] = "-f"; + free2 = argv[i++] = get_httpd_config (argv[0]); + argv[i++] = "-C"; + free3 = argv[i++] = g_strdup_printf ("Listen %d", port); + + client = mateconf_client_get_default (); + str = mateconf_client_get_string (client, + FILE_SHARING_REQUIRE_PASSWORD, NULL); + + if (str && strcmp (str, "never") == 0) { + /* Do nothing */ + } else if (str && strcmp (str, "on_write") == 0){ + argv[i++] = "-D"; + argv[i++] = "RequirePasswordOnWrite"; + } else { + /* always, or safe fallback */ + argv[i++] = "-D"; + argv[i++] = "RequirePasswordAlways"; + } + g_free (str); + g_object_unref (client); + + argv[i] = NULL; + + i = 0; + free4 = env[i++] = g_strdup_printf ("HOME=%s", g_get_home_dir()); + free5 = env[i++] = g_strdup_printf ("XDG_PUBLICSHARE_DIR=%s", public_dir); + free6 = env[i++] = g_strdup_printf ("XDG_CONFIG_HOME=%s", g_get_user_config_dir ()); + free7 = env[i++] = g_strdup_printf ("GUS_SHARE_NAME=%s", get_share_name ()); + free8 = env[i++] = g_strdup_printf ("GUS_LOGIN_LABEL=%s", "Please log in as the user guest"); + free9 = env[i++] = g_strdup_printf ("HTTP_MODULES_PATH=%s",get_httpd_modules_path ()); + env[i++] = "LANG=C"; + env[i] = NULL; + + pid_filename = g_build_filename (g_get_user_config_dir (), "user-share", "pid", NULL); + + /* Remove pid file before spawning to avoid races with child and old pidfile */ + unlink (pid_filename); + + error = NULL; + res = g_spawn_sync (g_get_home_dir(), + argv, env, 0, + httpd_child_setup, NULL, + NULL, NULL, + &status, + &error); + g_free (free1); + g_free (free2); + g_free (free3); + g_free (free4); + g_free (free5); + g_free (free6); + g_free (free7); + g_free (free8); + g_free (free9); + g_free (public_dir); + + if (!res) { + fprintf (stderr, "error spawning httpd: %s\n", + error->message); + g_error_free (error); + return FALSE; + } + + if (status != 0) { + g_free (pid_filename); + return FALSE; + } + + got_pidfile = FALSE; + error = NULL; + for (i = 0; i < 5; i++) { + if (error != NULL) + g_error_free (error); + error = NULL; + if (g_file_get_contents (pid_filename, &pidfile, NULL, &error)) { + got_pidfile = TRUE; + *pid_out = atoi (pidfile); + g_free (pidfile); + break; + } + sleep (1); + } + + g_free (pid_filename); + + if (!got_pidfile) { + fprintf (stderr, "error opening httpd pidfile: %s\n", error->message); + g_error_free (error); + return FALSE; + } + return TRUE; +} + +static void +kill_httpd (void) +{ + if (httpd_pid != 0) { + kill (httpd_pid, SIGTERM); + + /* Allow child time to die, we can't waitpid, because its + not a direct child */ + sleep (1); + } + httpd_pid = 0; +} + +void +http_up (void) +{ + guint port; + + port = get_port (); + if (!spawn_httpd (port, &httpd_pid)) { + fprintf (stderr, "spawning httpd failed\n"); + } +} + +void +http_down (void) +{ + kill_httpd (); +} + +gboolean +http_init (void) +{ +#ifdef HAVE_DBUS_1_1 + init_dbus(); +#endif + + return TRUE; +} + +pid_t +http_get_pid (void) +{ + return httpd_pid; +} diff --git a/src/http.h b/src/http.h new file mode 100644 index 0000000..b3ea42b --- /dev/null +++ b/src/http.h @@ -0,0 +1,27 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ + +/* + * Copyright (C) 2004-2008 Red Hat, Inc. + * + * Caja is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Caja is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Alexander Larsson <[email protected]> + * + */ + +void http_up (void); +void http_down (void); +gboolean http_init (void); +pid_t http_get_pid (void); diff --git a/src/marshal.list b/src/marshal.list new file mode 100644 index 0000000..05bd165 --- /dev/null +++ b/src/marshal.list @@ -0,0 +1 @@ +VOID:STRING,STRING,UINT64 diff --git a/src/obexftp.c b/src/obexftp.c new file mode 100644 index 0000000..6d94c97 --- /dev/null +++ b/src/obexftp.c @@ -0,0 +1,162 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ + +/* + * Copyright (C) 2004-2008 Red Hat, Inc. + * + * Caja is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Caja is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Bastien Nocera <[email protected]> + * + */ + +#include "config.h" + +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> +#include <mateconf/mateconf-client.h> + +#include <string.h> + +#include "obexftp.h" +#include "user_share-common.h" +#include "user_share-private.h" + +static DBusGConnection *connection = NULL; +static DBusGProxy *manager_proxy = NULL; +static DBusGProxy *server_proxy = NULL; + +void +obexftp_up (void) +{ + GError *err = NULL; + MateConfClient *client; + char *public_dir, *server; + gboolean allow_write, require_pairing; + + client = mateconf_client_get_default (); + require_pairing = mateconf_client_get_bool (client, FILE_SHARING_BLUETOOTH_REQUIRE_PAIRING, NULL); + + server = NULL; + if (manager_proxy == NULL) { + manager_proxy = dbus_g_proxy_new_for_name (connection, + "org.openobex", + "/org/openobex", + "org.openobex.Manager"); + if (dbus_g_proxy_call (manager_proxy, "CreateBluetoothServer", + &err, G_TYPE_STRING, "00:00:00:00:00:00", G_TYPE_STRING, "ftp", G_TYPE_BOOLEAN, require_pairing, G_TYPE_INVALID, + DBUS_TYPE_G_OBJECT_PATH, &server, G_TYPE_INVALID) == FALSE) { + g_printerr ("Creating Bluetooth ObexFTP server failed: %s\n", + err->message); + g_error_free (err); + g_object_unref (manager_proxy); + manager_proxy = NULL; + return; + } + } + + public_dir = lookup_public_dir (); + allow_write = mateconf_client_get_bool (client, FILE_SHARING_BLUETOOTH_ALLOW_WRITE, NULL); + g_object_unref (client); + + if (server_proxy == NULL) { + server_proxy = dbus_g_proxy_new_for_name (connection, + "org.openobex", + server, + "org.openobex.Server"); + g_free (server); + } + if (dbus_g_proxy_call (server_proxy, "Start", &err, + G_TYPE_STRING, public_dir, G_TYPE_BOOLEAN, allow_write, G_TYPE_BOOLEAN, TRUE, G_TYPE_INVALID, + G_TYPE_INVALID) == FALSE) { + if (g_error_matches (err, DBUS_GERROR, DBUS_GERROR_REMOTE_EXCEPTION) != FALSE && + dbus_g_error_has_name (err, "org.openobex.Error.Started") != FALSE) { + g_error_free (err); + g_message ("already started, ignoring error"); + g_free (public_dir); + return; + } + g_printerr ("Starting Bluetooth ObexFTP server failed: %s\n", + err->message); + g_error_free (err); + g_free (public_dir); + g_object_unref (server_proxy); + server_proxy = NULL; + g_object_unref (manager_proxy); + manager_proxy = NULL; + return; + } + + g_free (public_dir); +} + +static void +obexftp_stop (gboolean stop_manager) +{ + GError *err = NULL; + + if (server_proxy == NULL) + return; + + if (dbus_g_proxy_call (server_proxy, "Close", &err, G_TYPE_INVALID, G_TYPE_INVALID) == FALSE) { + if (err == NULL || + g_error_matches (err, DBUS_GERROR, DBUS_GERROR_REMOTE_EXCEPTION) == FALSE || + dbus_g_error_has_name (err, "org.openobex.Error.NotStarted") == FALSE) { + if (err != NULL) { + g_printerr ("Stopping Bluetooth ObexFTP server failed: %s\n", + err->message); + g_error_free (err); + } + return; + } + g_error_free (err); + } + + if (stop_manager != FALSE) { + g_object_unref (server_proxy); + server_proxy = NULL; + g_object_unref (manager_proxy); + manager_proxy = NULL; + } +} + +void +obexftp_down (void) +{ + obexftp_stop (TRUE); +} + +void +obexftp_restart (void) +{ + obexftp_stop (FALSE); + obexftp_up (); +} + +gboolean +obexftp_init (void) +{ + GError *err = NULL; + + connection = dbus_g_bus_get (DBUS_BUS_SESSION, &err); + if (connection == NULL) { + g_printerr ("Connecting to session bus failed: %s\n", + err->message); + g_error_free (err); + return FALSE; + } + + dbus_connection_set_exit_on_disconnect (dbus_g_connection_get_connection (connection), FALSE); + return TRUE; +} diff --git a/src/obexftp.h b/src/obexftp.h new file mode 100644 index 0000000..c199fd1 --- /dev/null +++ b/src/obexftp.h @@ -0,0 +1,29 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ + +/* + * Copyright (C) 2004-2008 Red Hat, Inc. + * + * Caja is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Caja is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Bastien Nocera <[email protected]> + * + */ + +#include <glib.h> + +void obexftp_up (void); +void obexftp_down (void); +void obexftp_restart (void); +gboolean obexftp_init (void); diff --git a/src/obexpush.c b/src/obexpush.c new file mode 100644 index 0000000..c7cb725 --- /dev/null +++ b/src/obexpush.c @@ -0,0 +1,563 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ + +/* + * Copyright (C) 2004-2008 Red Hat, Inc. + * + * Caja is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Caja is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Bastien Nocera <[email protected]> + * + */ + +#include "config.h" + +#include <glib.h> +#include <glib/gi18n.h> +#include <gio/gio.h> +#include <gdk/gdk.h> +#include <gtk/gtk.h> +#include <libmatenotify/notify.h> +#include <dbus/dbus-glib.h> +#include <mateconf/mateconf-client.h> +#include <dbus/dbus-glib-lowlevel.h> +#include <canberra-gtk.h> + +#include <string.h> + +#include "marshal.h" +#include "obexpush.h" +#include "user_share.h" +#include "user_share-private.h" + +#define DBUS_TYPE_G_STRING_VARIANT_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING)) + +static DBusGConnection *connection = NULL; +static DBusGProxy *manager_proxy = NULL; +static DBusGProxy *server_proxy = NULL; +static AcceptSetting accept_setting = -1; +static gboolean show_notifications = FALSE; + +static GtkStatusIcon *statusicon = NULL; +static guint num_notifications = 0; + +static void +hide_statusicon (void) +{ + num_notifications--; + if (num_notifications == 0) + gtk_status_icon_set_visible (statusicon, FALSE); +} + +static void +on_close_notification (NotifyNotification *notification) +{ + hide_statusicon (); + g_object_unref (notification); +} + +static void +notification_launch_action_on_file_cb (NotifyNotification *notification, + const char *action, + const char *file_uri) +{ + GdkScreen *screen; + GAppLaunchContext *ctx; + GTimeVal val; + + g_assert (action != NULL); + + g_get_current_time (&val); + +#if GTK_CHECK_VERSION(2,14,0) + ctx = G_APP_LAUNCH_CONTEXT (gdk_app_launch_context_new ()); + screen = gdk_screen_get_default (); + gdk_app_launch_context_set_screen (GDK_APP_LAUNCH_CONTEXT (ctx), screen); + gdk_app_launch_context_set_timestamp (GDK_APP_LAUNCH_CONTEXT (ctx), val.tv_sec); +#else + ctx = NULL; + screen = NULL; +#endif + + /* We launch the file viewer for the file */ + if (g_str_equal (action, "display") != FALSE) { + if (g_app_info_launch_default_for_uri (file_uri, ctx, NULL) == FALSE) { + g_warning ("Failed to launch the file viewer\n"); + } + } + + /* we open the Downloads folder */ + if (g_str_equal (action, "reveal") != FALSE) { + GFile *file; + GFile *parent; + gchar *parent_uri; + + file = g_file_new_for_uri (file_uri); + parent = g_file_get_parent (file); + parent_uri = g_file_get_uri (parent); + g_object_unref (file); + g_object_unref (parent); + + if (!g_app_info_launch_default_for_uri (parent_uri, ctx, NULL)) { + g_warning ("Failed to launch the file manager\n"); + } + + g_free (parent_uri); + } + + notify_notification_close (notification, NULL); + /* No need to call hide_statusicon(), closing the notification + * will call the close callback */ +} + +static void +show_notification (const char *filename) +{ + char *file_uri, *notification_text, *display, *mime_type; + NotifyNotification *notification; + ca_context *ctx; + GAppInfo *app; + + file_uri = g_filename_to_uri (filename, NULL, NULL); + if (file_uri == NULL) { + g_warning ("Could not make a filename from '%s'", filename); + return; + } + + display = g_filename_display_basename (filename); + /* Translators: %s is the name of the filename received */ + notification_text = g_strdup_printf(_("You received \"%s\" via Bluetooth"), display); + g_free (display); + notification = notify_notification_new (_("You received a file"), + notification_text, + "dialog-information"); + + notify_notification_set_timeout (notification, NOTIFY_EXPIRES_DEFAULT); + + mime_type = g_content_type_guess (filename, NULL, 0, NULL); + app = g_app_info_get_default_for_type (mime_type, FALSE); + if (app != NULL) { + g_object_unref (app); + notify_notification_add_action (notification, "display", _("Open File"), + (NotifyActionCallback) notification_launch_action_on_file_cb, + g_strdup (file_uri), (GFreeFunc) g_free); + } + notify_notification_add_action (notification, "reveal", _("Reveal File"), + (NotifyActionCallback) notification_launch_action_on_file_cb, + g_strdup (file_uri), (GFreeFunc) g_free); + + g_free (file_uri); + + g_signal_connect (G_OBJECT (notification), "closed", G_CALLBACK (on_close_notification), notification); + + if (!notify_notification_show (notification, NULL)) { + g_warning ("failed to send notification\n"); + } + g_free (notification_text); + + /* Now we do the audio notification */ + ctx = ca_gtk_context_get (); + ca_context_play (ctx, 0, + CA_PROP_EVENT_ID, "complete-download", + CA_PROP_EVENT_DESCRIPTION, _("File reception complete"), + NULL); +} + +static void +show_icon (void) +{ + if (statusicon == NULL) { + statusicon = gtk_status_icon_new_from_icon_name ("mate-obex-server"); + } else { + gtk_status_icon_set_visible (statusicon, TRUE); + } + num_notifications++; +} + +static gboolean +device_is_authorised (const char *bdaddr) +{ + DBusGConnection *connection; + DBusGProxy *manager; + GError *error = NULL; + GPtrArray *adapters; + gboolean retval = FALSE; + guint i; + + connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL); + if (connection == NULL) + return FALSE; + + manager = dbus_g_proxy_new_for_name (connection, "org.bluez", + "/", "org.bluez.Manager"); + if (manager == NULL) { + dbus_g_connection_unref (connection); + return FALSE; + } + + if (dbus_g_proxy_call (manager, "ListAdapters", &error, G_TYPE_INVALID, dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &adapters, G_TYPE_INVALID) == FALSE) { + g_object_unref (manager); + dbus_g_connection_unref (connection); + return FALSE; + } + + for (i = 0; i < adapters->len; i++) { + DBusGProxy *adapter, *device; + char *device_path; + GHashTable *props; + + g_message ("checking adapter %s", g_ptr_array_index (adapters, i)); + + adapter = dbus_g_proxy_new_for_name (connection, "org.bluez", + g_ptr_array_index (adapters, i), "org.bluez.Adapter"); + + if (dbus_g_proxy_call (adapter, "FindDevice", NULL, + G_TYPE_STRING, bdaddr, G_TYPE_INVALID, + DBUS_TYPE_G_OBJECT_PATH, &device_path, G_TYPE_INVALID) == FALSE) + { + g_object_unref (adapter); + continue; + } + + device = dbus_g_proxy_new_for_name (connection, "org.bluez", device_path, "org.bluez.Device"); + + if (dbus_g_proxy_call (device, "GetProperties", NULL, + G_TYPE_INVALID, dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), + &props, G_TYPE_INVALID) != FALSE) + { + GValue *value; + gboolean bonded; + + value = g_hash_table_lookup (props, "Paired"); + bonded = g_value_get_boolean (value); + g_message ("%s is %s", bdaddr, bonded ? "bonded" : "not bonded"); + + if (bonded) { + g_hash_table_destroy (props); + g_object_unref (device); + g_object_unref (adapter); + retval = TRUE; + break; + } + } + g_object_unref(adapter); + } + + g_ptr_array_free (adapters, TRUE); + + g_object_unref(manager); + dbus_g_connection_unref(connection); + + return retval; +} + +static void +transfer_started_cb (DBusGProxy *session, + const char *filename, + const char *local_path, + guint64 size, + gpointer user_data) +{ + GHashTable *dict; + DBusGProxy *server = (DBusGProxy *) user_data; + GError *error = NULL; + gboolean authorise; + + g_message ("transfer started on %s", local_path); + g_object_set_data_full (G_OBJECT (session), "filename", g_strdup (local_path), (GDestroyNotify) g_free); + + show_icon (); + + /* First transfer of the session */ + if (g_object_get_data (G_OBJECT (session), "bdaddr") == NULL) { + const char *bdaddr; + + if (dbus_g_proxy_call (server, "GetServerSessionInfo", &error, + DBUS_TYPE_G_OBJECT_PATH, dbus_g_proxy_get_path (session), G_TYPE_INVALID, + DBUS_TYPE_G_STRING_VARIANT_HASHTABLE, &dict, G_TYPE_INVALID) == FALSE) { + g_printerr ("Getting Server session info failed: %s\n", + error->message); + g_error_free (error); + return; + } + + bdaddr = g_hash_table_lookup (dict, "BluetoothAddress"); + g_message ("transfer started for device %s", bdaddr); + + g_object_set_data_full (G_OBJECT (session), "bdaddr", g_strdup (bdaddr), (GDestroyNotify) g_free); + /* Initial accept method is undefined, we do that lower down */ + g_object_set_data (G_OBJECT (session), "accept-method", GINT_TO_POINTER (-1)); + g_hash_table_destroy (dict); + } + + /* Accept method changed */ + if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (session), "accept-method")) != accept_setting) { + const char *bdaddr; + + bdaddr = g_object_get_data (G_OBJECT (session), "bdaddr"); + + if (bdaddr == NULL) { + g_warning ("Couldn't get the Bluetooth address for the device, rejecting the transfer"); + authorise = FALSE; + } else if (accept_setting == ACCEPT_ALWAYS) { + authorise = TRUE; + } else if (accept_setting == ACCEPT_BONDED) { + authorise = device_is_authorised (bdaddr); + } else { + //FIXME implement + g_warning ("\"Ask\" authorisation method not implemented"); + authorise = FALSE; + } + g_object_set_data (G_OBJECT (session), "authorise", GINT_TO_POINTER (authorise)); + } + + g_message ("accept_setting: %d", accept_setting); + + authorise = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (session), "authorise")); + if (authorise != FALSE) { + if (dbus_g_proxy_call (session, "Accept", &error, G_TYPE_INVALID, G_TYPE_INVALID) == FALSE) { + g_printerr ("Failed to accept file transfer: %s\n", error->message); + g_error_free (error); + return; + } + g_message ("authorised transfer"); + } else { + if (dbus_g_proxy_call (session, "Reject", &error, G_TYPE_INVALID, G_TYPE_INVALID) == FALSE) { + g_printerr ("Failed to reject file transfer: %s\n", error->message); + g_error_free (error); + return; + } + g_message ("rejected transfer"); + g_object_set_data (G_OBJECT (session), "filename", NULL); + } +} + +static void +transfer_completed_cb (DBusGProxy *session, + gpointer user_data) +{ + MateConfClient *client; + gboolean display_notify; + const char *filename; + + filename = (const char *) g_object_get_data (G_OBJECT (session), "filename"); + + g_message ("file finish transfer: %s", filename); + + if (filename == NULL) + return; + + client = mateconf_client_get_default (); + display_notify = mateconf_client_get_bool (client, FILE_SHARING_BLUETOOTH_OBEXPUSH_NOTIFY, NULL); + g_object_unref (client); + + if (display_notify) { + show_notification (filename); + } else { + hide_statusicon (); + } + g_object_set_data (G_OBJECT (session), "filename", NULL); +} + +static void +cancelled_cb (DBusGProxy *session, + gpointer user_data) +{ + //FIXME implement properly, we never actually finished the transfer + g_message ("transfered was cancelled by the sender"); + transfer_completed_cb (session, user_data); + hide_statusicon (); +} + +static void +error_occurred_cb (DBusGProxy *session, + const char *error_name, + const char *error_message, + gpointer user_data) +{ + //FIXME implement properly + g_message ("transfer error occurred: %s", error_message); + transfer_completed_cb (session, user_data); +} + +static void +session_created_cb (DBusGProxy *server, const char *session_path, gpointer user_data) +{ + DBusGProxy *session; + + session = dbus_g_proxy_new_for_name (connection, + "org.openobex", + session_path, + "org.openobex.ServerSession"); + + dbus_g_proxy_add_signal (session, "TransferStarted", + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(session, "TransferStarted", + G_CALLBACK (transfer_started_cb), server, NULL); + dbus_g_proxy_add_signal (session, "TransferCompleted", + G_TYPE_INVALID, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(session, "TransferCompleted", + G_CALLBACK (transfer_completed_cb), server, NULL); + dbus_g_proxy_add_signal (session, "Cancelled", + G_TYPE_INVALID, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(session, "Cancelled", + G_CALLBACK (cancelled_cb), server, NULL); + dbus_g_proxy_add_signal (session, "ErrorOccurred", + G_TYPE_INVALID, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(session, "ErrorOccurred", + G_CALLBACK (error_occurred_cb), server, NULL); +} + +void +obexpush_up (void) +{ + GError *err = NULL; + char *download_dir, *server; + + server = NULL; + if (manager_proxy == NULL) { + manager_proxy = dbus_g_proxy_new_for_name (connection, + "org.openobex", + "/org/openobex", + "org.openobex.Manager"); + if (dbus_g_proxy_call (manager_proxy, "CreateBluetoothServer", + &err, G_TYPE_STRING, "00:00:00:00:00:00", G_TYPE_STRING, "opp", G_TYPE_BOOLEAN, FALSE, G_TYPE_INVALID, + DBUS_TYPE_G_OBJECT_PATH, &server, G_TYPE_INVALID) == FALSE) { + g_printerr ("Creating Bluetooth ObexPush server failed: %s\n", + err->message); + g_error_free (err); + g_object_unref (manager_proxy); + manager_proxy = NULL; + return; + } + } + + download_dir = lookup_download_dir (); + + if (server_proxy == NULL) { + server_proxy = dbus_g_proxy_new_for_name (connection, + "org.openobex", + server, + "org.openobex.Server"); + g_free (server); + + dbus_g_proxy_add_signal (server_proxy, "SessionCreated", + DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(server_proxy, "SessionCreated", + G_CALLBACK (session_created_cb), NULL, NULL); + } + + if (dbus_g_proxy_call (server_proxy, "Start", &err, + G_TYPE_STRING, download_dir, G_TYPE_BOOLEAN, TRUE, G_TYPE_BOOLEAN, FALSE, G_TYPE_INVALID, + G_TYPE_INVALID) == FALSE) { + if (g_error_matches (err, DBUS_GERROR, DBUS_GERROR_REMOTE_EXCEPTION) != FALSE && + dbus_g_error_has_name (err, "org.openobex.Error.Started") != FALSE) { + g_error_free (err); + g_message ("already started, ignoring error"); + g_free (download_dir); + return; + } + g_printerr ("Starting Bluetooth ObexPush server failed: %s\n", + err->message); + g_error_free (err); + g_free (download_dir); + g_object_unref (server_proxy); + server_proxy = NULL; + g_object_unref (manager_proxy); + manager_proxy = NULL; + return; + } + + g_free (download_dir); +} + +static void +obexpush_stop (gboolean stop_manager) +{ + GError *err = NULL; + + if (server_proxy == NULL) + return; + + if (dbus_g_proxy_call (server_proxy, "Close", &err, G_TYPE_INVALID, G_TYPE_INVALID) == FALSE) { + if (g_error_matches (err, DBUS_GERROR, DBUS_GERROR_REMOTE_EXCEPTION) == FALSE || + dbus_g_error_has_name (err, "org.openobex.Error.NotStarted") == FALSE) { + g_printerr ("Stopping Bluetooth ObexPush server failed: %s\n", + err->message); + g_error_free (err); + return; + } + g_error_free (err); + } + + if (stop_manager != FALSE) { + g_object_unref (server_proxy); + server_proxy = NULL; + g_object_unref (manager_proxy); + manager_proxy = NULL; + } + + //FIXME stop all the notifications +} + +void +obexpush_down (void) +{ + obexpush_stop (TRUE); +} + +void +obexpush_restart (void) +{ + obexpush_stop (FALSE); + obexpush_up (); +} + +gboolean +obexpush_init (void) +{ + GError *err = NULL; + + connection = dbus_g_bus_get (DBUS_BUS_SESSION, &err); + if (connection == NULL) { + g_printerr ("Connecting to session bus failed: %s\n", + err->message); + g_error_free (err); + return FALSE; + } + + dbus_g_object_register_marshaller (marshal_VOID__STRING_STRING_UINT64, + G_TYPE_NONE, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_INVALID); + + if (!notify_init("mate-user-share")) { + g_warning("Unable to initialize the notification system\n"); + } + + dbus_connection_set_exit_on_disconnect (dbus_g_connection_get_connection (connection), FALSE); + + return TRUE; +} + +void +obexpush_set_accept_files_policy (AcceptSetting setting) +{ + accept_setting = setting; +} + +void +obexpush_set_notify (gboolean enabled) +{ + show_notifications = enabled; +} diff --git a/src/obexpush.h b/src/obexpush.h new file mode 100644 index 0000000..3ac624c --- /dev/null +++ b/src/obexpush.h @@ -0,0 +1,32 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ + +/* + * Copyright (C) 2004-2008 Red Hat, Inc. + * + * Caja is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Caja is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Bastien Nocera <[email protected]> + * + */ + +#include <glib.h> +#include "user_share-private.h" + +void obexpush_up (void); +void obexpush_down (void); +void obexpush_restart (void); +gboolean obexpush_init (void); +void obexpush_set_accept_files_policy (AcceptSetting accept_setting); +void obexpush_set_notify (gboolean enabled); diff --git a/src/share-extension.c b/src/share-extension.c new file mode 100644 index 0000000..59aead6 --- /dev/null +++ b/src/share-extension.c @@ -0,0 +1,299 @@ +/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8; tab-width: 8 -*- + * + * Copyright (C) 2003 Novell, Inc. + * Copyright (C) 2003-2004 Red Hat, Inc. + * Copyright (C) 2005 William Jon McCann <[email protected]> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> +#include <glib/gi18n-lib.h> +#include <gtk/gtk.h> +#include <libcaja-extension/caja-menu-provider.h> +#include <libcaja-extension/caja-location-widget-provider.h> + +#include "caja-share-bar.h" +#include "user_share-common.h" + +#define CAJA_TYPE_USER_SHARE (caja_user_share_get_type ()) +#define CAJA_USER_SHARE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CAJA_TYPE_USER_SHARE, CajaUserShare)) +#define CAJA_IS_USER_SHARE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CAJA_TYPE_USER_SHARE)) + +typedef struct _CajaUserSharePrivate CajaUserSharePrivate; + +typedef struct +{ + GObject parent_slot; + CajaUserSharePrivate *priv; +} CajaUserShare; + +typedef struct +{ + GObjectClass parent_slot; +} CajaUserShareClass; + +#define CAJA_USER_SHARE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CAJA_TYPE_USER_SHARE, CajaUserSharePrivate)) + +struct _CajaUserSharePrivate +{ + GSList *widget_list; +}; + +static GType caja_user_share_get_type (void); +static void caja_user_share_register_type (GTypeModule *module); + +static GObjectClass *parent_class; + + +static void +launch_process (char **argv, GtkWindow *parent) +{ + GError *error; + GtkWidget *dialog; + + error = NULL; + if (!g_spawn_async (NULL, + argv, NULL, + 0, + NULL, NULL, + NULL, + &error)) { + + + dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK, _("Unable to launch the Personal File Sharing preferences")); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + g_error_free (error); + } +} + +static void +launch_prefs_on_window (GtkWindow *window) +{ + char *argv [2]; + + argv [0] = g_build_filename (BINDIR, "mate-file-share-properties", NULL); + argv [1] = NULL; + + launch_process (argv, window); + + g_free (argv [0]); +} + +static void +bar_activated_cb (CajaShareBar *bar, + gpointer data) +{ + launch_prefs_on_window (GTK_WINDOW (data)); +} + +static void +destroyed_callback (GtkWidget *widget, + CajaUserShare *share) +{ + share->priv->widget_list = g_slist_remove (share->priv->widget_list, widget); +} + +static void +add_widget (CajaUserShare *share, + GtkWidget *widget) +{ + share->priv->widget_list = g_slist_prepend (share->priv->widget_list, widget); + + g_signal_connect (widget, "destroy", + G_CALLBACK (destroyed_callback), + share); +} + +static GtkWidget * +caja_user_share_get_location_widget (CajaLocationWidgetProvider *iface, + const char *uri, + GtkWidget *window) +{ + GFile *file; + GtkWidget *bar; + CajaUserShare *share; + guint i; + gboolean enable = FALSE; + GFile *home; + const GUserDirectory special_dirs[] = { G_USER_DIRECTORY_PUBLIC_SHARE, G_USER_DIRECTORY_DOWNLOAD }; + gboolean is_dir[] = { FALSE, FALSE }; + + file = g_file_new_for_uri (uri); + home = g_file_new_for_path (g_get_home_dir ()); + + /* We don't show anything in $HOME */ + if (g_file_equal (home, file)) { + g_object_unref (home); + g_object_unref (file); + return NULL; + } + + g_object_unref (home); + + for (i = 0; i < G_N_ELEMENTS (special_dirs); i++) { + GFile *dir; + dir = lookup_dir_with_fallback (special_dirs[i]); + if (g_file_equal (dir, file)) { + enable = TRUE; + is_dir[i] = TRUE; + } + g_object_unref (dir); + } + + if (enable == FALSE) + return NULL; + + share = CAJA_USER_SHARE (iface); + + if (is_dir[0] != FALSE && is_dir[1] != FALSE) { + bar = caja_share_bar_new (_("You can share files from this folder and receive files to it")); + } else if (is_dir[0] != FALSE) { + bar = caja_share_bar_new (_("You can share files from this folder over the network and Bluetooth")); + } else { + bar = caja_share_bar_new (_("You can receive files over Bluetooth into this folder")); + } + + add_widget (share, caja_share_bar_get_button (CAJA_SHARE_BAR (bar))); + + g_signal_connect (bar, "activate", + G_CALLBACK (bar_activated_cb), + window); + + gtk_widget_show (bar); + + g_object_unref (file); + + return bar; +} + +static void +caja_user_share_location_widget_provider_iface_init (CajaLocationWidgetProviderIface *iface) +{ + iface->get_widget = caja_user_share_get_location_widget; +} + +static void +caja_user_share_instance_init (CajaUserShare *share) +{ + share->priv = CAJA_USER_SHARE_GET_PRIVATE (share); +} + +static void +caja_user_share_finalize (GObject *object) +{ + CajaUserShare *share; + + g_return_if_fail (object != NULL); + g_return_if_fail (CAJA_IS_USER_SHARE (object)); + + share = CAJA_USER_SHARE (object); + + g_return_if_fail (share->priv != NULL); + + if (share->priv->widget_list != NULL) { + g_slist_free (share->priv->widget_list); + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +caja_user_share_class_init (CajaUserShareClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = caja_user_share_finalize; + + g_type_class_add_private (klass, sizeof (CajaUserSharePrivate)); +} + +static GType share_type = 0; + +static GType +caja_user_share_get_type (void) +{ + return share_type; +} + +static void +caja_user_share_register_type (GTypeModule *module) +{ + static const GTypeInfo info = { + sizeof (CajaUserShareClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) caja_user_share_class_init, + NULL, + NULL, + sizeof (CajaUserShare), + 0, + (GInstanceInitFunc) caja_user_share_instance_init, + }; + + static const GInterfaceInfo location_widget_provider_iface_info = { + (GInterfaceInitFunc) caja_user_share_location_widget_provider_iface_init, + NULL, + NULL + }; + + share_type = g_type_module_register_type (module, + G_TYPE_OBJECT, + "CajaUserShare", + &info, 0); + + g_type_module_add_interface (module, + share_type, + CAJA_TYPE_LOCATION_WIDGET_PROVIDER, + &location_widget_provider_iface_info); +} + +void +caja_module_initialize (GTypeModule *module) +{ + caja_user_share_register_type (module); + bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); +} + +void +caja_module_shutdown (void) +{ +} + +void +caja_module_list_types (const GType **types, + int *num_types) +{ + static GType type_list [1]; + + type_list[0] = CAJA_TYPE_USER_SHARE; + + *types = type_list; + *num_types = 1; +} diff --git a/src/user_share-common.c b/src/user_share-common.c new file mode 100644 index 0000000..ae2fd2c --- /dev/null +++ b/src/user_share-common.c @@ -0,0 +1,89 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ + +/* + * Copyright (C) 2004-2009 Red Hat, Inc. + * + * Caja is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Caja is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Alexander Larsson <[email protected]> + * Bastien Nocera <[email protected]> + * + */ + +#include "user_share-common.h" + +static char * +lookup_special_dir (GUserDirectory directory, + const char *name, + gboolean create_dir) +{ + const char *special_dir; + char *dir; + + special_dir = g_get_user_special_dir (directory); + if (special_dir != NULL && strcmp (special_dir, g_get_home_dir ()) != 0) { + if (create_dir != FALSE) + g_mkdir_with_parents (special_dir, 0755); + return g_strdup (special_dir); + } + + dir = g_build_filename (g_get_home_dir (), name, NULL); + if (create_dir != FALSE) + g_mkdir_with_parents (dir, 0755); + return dir; +} + +char * +lookup_public_dir (void) +{ + return lookup_special_dir (G_USER_DIRECTORY_PUBLIC_SHARE, + "Public", + TRUE); +} + +char * +lookup_download_dir (void) +{ + return lookup_special_dir (G_USER_DIRECTORY_DOWNLOAD, + "Downloads", + TRUE); +} + +GFile * +lookup_dir_with_fallback (GUserDirectory directory) +{ + GFile *file; + char *path; + const char *name; + + if (directory == G_USER_DIRECTORY_PUBLIC_SHARE) + name = "Public"; + else if (directory == G_USER_DIRECTORY_DOWNLOAD) + name = "Downloads"; + else + g_assert_not_reached (); + + path = lookup_special_dir (directory, + name, + FALSE); + + if (path == NULL) + return NULL; + + file = g_file_new_for_path (path); + g_free (path); + + return file; +} diff --git a/src/user_share-common.h b/src/user_share-common.h new file mode 100644 index 0000000..d2895ad --- /dev/null +++ b/src/user_share-common.h @@ -0,0 +1,30 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ + +/* + * Copyright (C) 2004-2009 Red Hat, Inc. + * + * Caja is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Caja is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Alexander Larsson <[email protected]> + * Bastien Nocera <[email protected]> + * + */ + +#include <glib.h> +#include <gio/gio.h> + +char *lookup_public_dir (void); +char *lookup_download_dir (void); +GFile *lookup_dir_with_fallback (GUserDirectory directory); diff --git a/src/user_share-private.c b/src/user_share-private.c new file mode 100644 index 0000000..4ffd12e --- /dev/null +++ b/src/user_share-private.c @@ -0,0 +1,102 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ + +/* + * Copyright (C) 2004-2008 Red Hat, Inc. + * + * Caja is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Caja is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Alexander Larsson <[email protected]> + * Bastien Nocera <[email protected]> + * + */ + +#include "config.h" + +#include <string.h> + +#include "user_share-private.h" + +static char *password_setting_strings[] = { + "never", + "on_write", + "always" +}; + +static char *accept_file_strings[] = { + "always", + "bonded", + "ask" +}; + +const char * +password_string_from_setting (PasswordSetting setting) +{ + + if (setting >= 0 && setting <= PASSWORD_ALWAYS) + return password_setting_strings[setting]; + + /* Fallback on secure pref */ + return password_setting_strings[PASSWORD_ALWAYS]; +} + +PasswordSetting +password_setting_from_string (const char *str) +{ + if (str != NULL) { + if (strcmp (str, "never") == 0) { + return PASSWORD_NEVER; + } + if (strcmp (str, "always") == 0) { + return PASSWORD_ALWAYS; + } + if (strcmp (str, "on_write") == 0) { + return PASSWORD_ON_WRITE; + } + } + + /* Fallback on secure pref */ + return PASSWORD_ALWAYS; +} + +const char * +accept_string_from_setting (AcceptSetting setting) +{ + + if (setting >= 0 && setting <= ACCEPT_ASK) + return accept_file_strings[setting]; + + /* Fallback on secure pref */ + return accept_file_strings[ACCEPT_BONDED]; +} + +AcceptSetting +accept_setting_from_string (const char *str) +{ + if (str != NULL) { + if (strcmp (str, "always") == 0) { + return ACCEPT_ALWAYS; + } + if (strcmp (str, "bonded") == 0 || + strcmp (str, "bonded_and_trusted") == 0) { + return ACCEPT_BONDED; + } + if (strcmp (str, "ask") == 0) { + return ACCEPT_ASK; + } + } + + /* Fallback on secure pref */ + return ACCEPT_BONDED; +} diff --git a/src/user_share-private.h b/src/user_share-private.h new file mode 100644 index 0000000..4ce936c --- /dev/null +++ b/src/user_share-private.h @@ -0,0 +1,57 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ + +/* + * Copyright (C) 2004-2008 Red Hat, Inc. + * + * Caja is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Caja is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Alexander Larsson <[email protected]> + * Bastien Nocera <[email protected]> + * + */ + +#ifndef _USER_SHARE_PRIVATE_H_ +#define _USER_SHARE_PRIVATE_H_ + +#define FILE_SHARING_DIR "/desktop/mate/file_sharing" +#define FILE_SHARING_ENABLED FILE_SHARING_DIR "/enabled" +#define FILE_SHARING_BLUETOOTH_ENABLED FILE_SHARING_DIR "/bluetooth_enabled" +#define FILE_SHARING_BLUETOOTH_OBEXPUSH_ENABLED FILE_SHARING_DIR "/bluetooth_obexpush_enabled" + +#define FILE_SHARING_REQUIRE_PASSWORD FILE_SHARING_DIR "/require_password" +#define FILE_SHARING_BLUETOOTH_ALLOW_WRITE FILE_SHARING_DIR "/bluetooth_allow_write" +#define FILE_SHARING_BLUETOOTH_REQUIRE_PAIRING FILE_SHARING_DIR "/bluetooth_require_pairing" +#define FILE_SHARING_BLUETOOTH_OBEXPUSH_ACCEPT_FILES FILE_SHARING_DIR "/bluetooth_accept_files" +#define FILE_SHARING_BLUETOOTH_OBEXPUSH_NOTIFY FILE_SHARING_DIR "/bluetooth_notify" + +typedef enum { + PASSWORD_NEVER, + PASSWORD_ON_WRITE, + PASSWORD_ALWAYS +} PasswordSetting; + +typedef enum { + ACCEPT_ALWAYS, + ACCEPT_BONDED, + ACCEPT_ASK +} AcceptSetting; + +const char *password_string_from_setting (PasswordSetting setting); +PasswordSetting password_setting_from_string (const char *str); + +const char *accept_string_from_setting (AcceptSetting setting); +AcceptSetting accept_setting_from_string (const char *str); + +#endif /* _USER_SHARE_PRIVATE_H_ */ diff --git a/src/user_share.c b/src/user_share.c new file mode 100644 index 0000000..e55863a --- /dev/null +++ b/src/user_share.c @@ -0,0 +1,572 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ + +/* + * Copyright (C) 2004-2008 Red Hat, Inc. + * + * Caja is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Caja is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Alexander Larsson <[email protected]> + * + */ + +#include "config.h" + +#include <gdk/gdkx.h> +#include <gtk/gtk.h> +#include <glib/gi18n.h> +#include <bluetooth-client.h> +#include <X11/Xlib.h> + +#include "user_share.h" +#include "user_share-private.h" +#include "user_share-common.h" +#include "http.h" +#include "obexftp.h" +#include "obexpush.h" + +#include <dbus/dbus.h> +#include <dbus/dbus-glib.h> + +#include <mateconf/mateconf-client.h> + +#include <stdarg.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> + +/* ConsoleKit */ +#define CK_NAME "org.freedesktop.ConsoleKit" +#define CK_INTERFACE "org.freedesktop.ConsoleKit" +#define CK_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager" +#define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager" +#define CK_SEAT_INTERFACE "org.freedesktop.ConsoleKit.Seat" +#define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session" + +static guint disabled_timeout_tag = 0; +static gboolean has_console = TRUE; + +static BluetoothClient *client = NULL; +static gboolean bluetoothd_enabled = FALSE; + +#define OBEX_ENABLED (bluetoothd_enabled && has_console) + +static void +obex_services_start (void) +{ + MateConfClient *client; + + if (bluetoothd_enabled == FALSE || + has_console == FALSE) + return; + + client = mateconf_client_get_default (); + + if (mateconf_client_get_bool (client, FILE_SHARING_BLUETOOTH_OBEXPUSH_ENABLED, NULL) == TRUE) { + obexpush_up (); + } + if (mateconf_client_get_bool (client, FILE_SHARING_BLUETOOTH_ENABLED, NULL) == TRUE) { + obexftp_up (); + } + + g_object_unref (client); +} + +static void +obex_services_shutdown (void) +{ + obexpush_down (); + obexftp_down (); +} + +static void +sessionchanged_cb (void) +{ + DBusGConnection *dbus_connection; + DBusGProxy *proxy_ck_manager; + DBusGProxy *proxy_ck_session; + + gchar *ck_session_path; + gboolean is_active = FALSE; + GError *error = NULL; + + g_message ("Active session changed"); + + dbus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (!dbus_connection) { + g_warning ("Unable to connect to dbus"); + dbus_g_connection_unref (dbus_connection); + return; + } + + proxy_ck_manager = dbus_g_proxy_new_for_name (dbus_connection, + CK_NAME, + CK_MANAGER_PATH, + CK_MANAGER_INTERFACE); + if (dbus_g_proxy_call (proxy_ck_manager, "GetCurrentSession", + &error, G_TYPE_INVALID, + DBUS_TYPE_G_OBJECT_PATH, &ck_session_path, + G_TYPE_INVALID) == FALSE) { + g_warning ("Couldn't request the name: %s", error->message); + dbus_g_connection_unref (dbus_connection); + g_object_unref (proxy_ck_manager); + g_error_free (error); + return; + } + + proxy_ck_session = dbus_g_proxy_new_for_name (dbus_connection, + CK_NAME, + ck_session_path, + CK_SESSION_INTERFACE); + + if (dbus_g_proxy_call (proxy_ck_session, "IsActive", + &error, G_TYPE_INVALID, + G_TYPE_BOOLEAN, &is_active, + G_TYPE_INVALID) == FALSE) { + + g_warning ("Couldn't request the name: %s", error->message); + dbus_g_connection_unref (dbus_connection); + g_object_unref (proxy_ck_manager); + g_object_unref (proxy_ck_session); + g_error_free (error); + return; + } + + has_console = is_active; + if (is_active) { + obex_services_start (); + } else { + obex_services_shutdown (); + } + + dbus_g_connection_unref (dbus_connection); + g_free (ck_session_path); + g_object_unref (proxy_ck_manager); + g_object_unref (proxy_ck_session); + if (error != NULL) { + g_error_free (error); + } +} + +static void +consolekit_init (void) +{ + DBusGConnection *dbus_connection; + DBusGProxy *proxy_ck_manager; + DBusGProxy *proxy_ck_session; + DBusGProxy *proxy_ck_seat; + gchar *ck_session_path; + gchar *ck_seat_path; + GError *error = NULL; + + dbus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL); + + if (!dbus_connection) { + g_warning ("Unable to connect to dbus"); + dbus_g_connection_unref (dbus_connection); + return; + } + + proxy_ck_manager = dbus_g_proxy_new_for_name (dbus_connection, + CK_NAME, + CK_MANAGER_PATH, + CK_MANAGER_INTERFACE); + if (dbus_g_proxy_call (proxy_ck_manager, "GetCurrentSession", + &error, G_TYPE_INVALID, + DBUS_TYPE_G_OBJECT_PATH, &ck_session_path, + G_TYPE_INVALID) == FALSE) { + + g_warning ("Couldn't request the name: %s", error->message); + g_object_unref (proxy_ck_manager); + return; + } + + proxy_ck_session = dbus_g_proxy_new_for_name (dbus_connection, + CK_NAME, + ck_session_path, + CK_SESSION_INTERFACE); + if (dbus_g_proxy_call (proxy_ck_session, "GetSeatId", + &error, G_TYPE_INVALID, + DBUS_TYPE_G_OBJECT_PATH, &ck_seat_path, + G_TYPE_INVALID) == FALSE) { + + g_warning ("Couldn't request the name: %s", error->message); + g_object_unref (proxy_ck_session); + return; + } + + proxy_ck_seat = dbus_g_proxy_new_for_name (dbus_connection, + CK_NAME, + ck_seat_path, + CK_SEAT_INTERFACE); + dbus_g_proxy_add_signal (proxy_ck_seat, "ActiveSessionChanged", + G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (proxy_ck_seat, "ActiveSessionChanged", + G_CALLBACK (sessionchanged_cb), NULL, NULL); + if (error != NULL) { + g_error_free (error); + } + g_object_unref (proxy_ck_manager); + g_object_unref (proxy_ck_session); + g_free (ck_seat_path); + dbus_g_connection_unref (dbus_connection); +} + +static void +default_adapter_changed (GObject *gobject, + GParamSpec *pspec, + gpointer user_data) +{ + char *adapter; + gboolean adapter_powered; + + g_object_get (G_OBJECT (client), + "default-adapter", &adapter, + "default-adapter-powered", &adapter_powered, + NULL); + if (adapter != NULL && *adapter != '\0') { + bluetoothd_enabled = adapter_powered; + } else { + bluetoothd_enabled = FALSE; + } + + /* Were we called as init, or as a callback */ + if (gobject != NULL) { + if (bluetoothd_enabled != FALSE) + obex_services_start (); + else + obex_services_shutdown (); + } +} + +static void +bluez_init (void) +{ + client = bluetooth_client_new (); + default_adapter_changed (NULL, NULL, NULL); + g_signal_connect (G_OBJECT (client), "notify::default-adapter", + G_CALLBACK (default_adapter_changed), NULL); + g_signal_connect (G_OBJECT (client), "notify::default-adapter-powered", + G_CALLBACK (default_adapter_changed), NULL); +} + +static void +migrate_old_configuration (void) +{ + const char *old_config_dir; + const char *new_config_dir; + + old_config_dir = g_build_filename (g_get_home_dir (), ".mate2", "user-share", NULL); + new_config_dir = g_build_filename (g_get_user_config_dir (), "user-share", NULL); + if (g_file_test (old_config_dir, G_FILE_TEST_IS_DIR)) + g_rename (old_config_dir, new_config_dir); + +} + +static void +require_password_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + /* Need to restart to get new password setting */ + if (http_get_pid () != 0) { + http_down (); + http_up (); + } +} + +/* File sharing was disabled for some time, exit now */ +/* If we re-enable it in the ui, this will be restarted anyway */ +static gboolean +disabled_timeout_callback (gpointer user_data) +{ + MateConfClient* client = (MateConfClient *) user_data; + http_down (); + + if (mateconf_client_get_bool (client, FILE_SHARING_BLUETOOTH_ENABLED, NULL) == FALSE && + mateconf_client_get_bool (client, FILE_SHARING_BLUETOOTH_OBEXPUSH_ENABLED, NULL) == FALSE) + _exit (0); + return FALSE; +} + +static void +file_sharing_enabled_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + gboolean enabled; + + if (disabled_timeout_tag != 0) { + g_source_remove (disabled_timeout_tag); + disabled_timeout_tag = 0; + } + + enabled = mateconf_client_get_bool (client, + FILE_SHARING_ENABLED, NULL); + if (enabled) { + if (http_get_pid () == 0) { + http_up (); + } + } else { + http_down (); + disabled_timeout_tag = g_timeout_add_seconds (3, + (GSourceFunc)disabled_timeout_callback, + client); + } +} + +static void +file_sharing_bluetooth_allow_write_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + if (mateconf_client_get_bool (client, FILE_SHARING_BLUETOOTH_ENABLED, NULL) != FALSE) + obexftp_restart (); +} + +static void +file_sharing_bluetooth_require_pairing_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + if (mateconf_client_get_bool (client, FILE_SHARING_BLUETOOTH_ENABLED, NULL) != FALSE) { + /* We need to fully reset the session, + * otherwise the new setting isn't taken into account */ + obexftp_down (); + obexftp_up (); + } +} + +static void +file_sharing_bluetooth_enabled_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + if (mateconf_client_get_bool (client, + FILE_SHARING_BLUETOOTH_ENABLED, NULL) == FALSE) { + obexftp_down (); + if (mateconf_client_get_bool (client, FILE_SHARING_ENABLED, NULL) == FALSE && + mateconf_client_get_bool (client, FILE_SHARING_BLUETOOTH_OBEXPUSH_ENABLED, NULL) == FALSE) { + _exit (0); + } + } else if (OBEX_ENABLED) { + obexftp_up (); + } +} + +static void +file_sharing_bluetooth_obexpush_enabled_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + if (mateconf_client_get_bool (client, + FILE_SHARING_BLUETOOTH_OBEXPUSH_ENABLED, NULL) == FALSE) { + obexpush_down (); + if (mateconf_client_get_bool (client, FILE_SHARING_ENABLED, NULL) == FALSE && + mateconf_client_get_bool (client, FILE_SHARING_BLUETOOTH_ENABLED, NULL) == FALSE) { + _exit (0); + } + } else if (OBEX_ENABLED) { + obexpush_up (); + } +} + +static void +file_sharing_bluetooth_obexpush_accept_files_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + AcceptSetting setting; + char *str; + + str = mateconf_client_get_string (client, FILE_SHARING_BLUETOOTH_OBEXPUSH_ACCEPT_FILES, NULL); + setting = accept_setting_from_string (str); + g_free (str); + + obexpush_set_accept_files_policy (setting); +} + +static void +file_sharing_bluetooth_obexpush_notify_changed (MateConfClient* client, + guint cnxn_id, + MateConfEntry *entry, + gpointer data) +{ + obexpush_set_notify (mateconf_client_get_bool (client, FILE_SHARING_BLUETOOTH_OBEXPUSH_NOTIFY, NULL)); +} + +static RETSIGTYPE +cleanup_handler (int sig) +{ + http_down (); + obexftp_down (); + obexpush_down (); + _exit (2); +} + +static int +x_io_error_handler (Display *xdisplay) +{ + http_down (); + obexftp_down (); + _exit (2); +} + +int +main (int argc, char **argv) +{ + MateConfClient *client; + Display *xdisplay; + int x_fd; + Window selection_owner; + Atom xatom; + + bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + gtk_init (&argc, &argv); + + if (g_strcmp0 (g_get_real_name (), "root") == 0) { + g_warning ("mate-user-share cannot be started as root for security reasons."); + return 1; + } + + signal (SIGPIPE, SIG_IGN); + signal (SIGINT, cleanup_handler); + signal (SIGHUP, cleanup_handler); + signal (SIGTERM, cleanup_handler); + + xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); + if (xdisplay == NULL) { + g_warning ("Can't open display"); + return 1; + } + + xatom = XInternAtom (xdisplay, "_MATE_USER_SHARE", FALSE); + selection_owner = XGetSelectionOwner (xdisplay, xatom); + + if (selection_owner != None) { + /* There is an owner already, quit */ + return 1; + } + + selection_owner = XCreateSimpleWindow (xdisplay, + RootWindow (xdisplay, 0), + 0, 0, 1, 1, + 0, 0, 0); + XSetSelectionOwner (xdisplay, xatom, selection_owner, CurrentTime); + + if (XGetSelectionOwner (xdisplay, xatom) != selection_owner) { + /* Didn't get the selection */ + return 1; + } + + migrate_old_configuration (); + + client = mateconf_client_get_default (); + if (mateconf_client_get_bool (client, FILE_SHARING_ENABLED, NULL) == FALSE && + mateconf_client_get_bool (client, FILE_SHARING_BLUETOOTH_ENABLED, NULL) == FALSE && + mateconf_client_get_bool (client, FILE_SHARING_BLUETOOTH_OBEXPUSH_ENABLED, NULL) == FALSE) + return 1; + + x_fd = ConnectionNumber (xdisplay); + XSetIOErrorHandler (x_io_error_handler); + + if (http_init () == FALSE) + return 1; + if (obexftp_init () == FALSE) + return 1; + if (obexpush_init () == FALSE) + return 1; + + mateconf_client_add_dir (client, + FILE_SHARING_DIR, + MATECONF_CLIENT_PRELOAD_RECURSIVE, + NULL); + + mateconf_client_notify_add (client, + FILE_SHARING_ENABLED, + file_sharing_enabled_changed, + NULL, + NULL, + NULL); + mateconf_client_notify_add (client, + FILE_SHARING_REQUIRE_PASSWORD, + require_password_changed, + NULL, + NULL, + NULL); + mateconf_client_notify_add (client, + FILE_SHARING_BLUETOOTH_ENABLED, + file_sharing_bluetooth_enabled_changed, + NULL, + NULL, + NULL); + mateconf_client_notify_add (client, + FILE_SHARING_BLUETOOTH_ALLOW_WRITE, + file_sharing_bluetooth_allow_write_changed, + NULL, + NULL, + NULL); + mateconf_client_notify_add (client, + FILE_SHARING_BLUETOOTH_REQUIRE_PAIRING, + file_sharing_bluetooth_require_pairing_changed, + NULL, + NULL, + NULL); + mateconf_client_notify_add (client, + FILE_SHARING_BLUETOOTH_OBEXPUSH_ENABLED, + file_sharing_bluetooth_obexpush_enabled_changed, + NULL, + NULL, + NULL); + mateconf_client_notify_add (client, + FILE_SHARING_BLUETOOTH_OBEXPUSH_ACCEPT_FILES, + file_sharing_bluetooth_obexpush_accept_files_changed, + NULL, + NULL, + NULL); + mateconf_client_notify_add (client, + FILE_SHARING_BLUETOOTH_OBEXPUSH_NOTIFY, + file_sharing_bluetooth_obexpush_notify_changed, + NULL, + NULL, + NULL); + + g_object_unref (client); + + bluez_init (); + consolekit_init (); + + /* Initial setting */ + file_sharing_enabled_changed (client, 0, NULL, NULL); + file_sharing_bluetooth_enabled_changed (client, 0, NULL, NULL); + file_sharing_bluetooth_obexpush_accept_files_changed (client, 0, NULL, NULL); + file_sharing_bluetooth_obexpush_notify_changed (client, 0, NULL, NULL); + file_sharing_bluetooth_obexpush_enabled_changed (client, 0, NULL, NULL); + + gtk_main (); + + return 0; +} diff --git a/src/user_share.h b/src/user_share.h new file mode 100644 index 0000000..1ce6f73 --- /dev/null +++ b/src/user_share.h @@ -0,0 +1,25 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ + +/* + * Copyright (C) 2004-2008 Red Hat, Inc. + * + * Caja is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Caja is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Alexander Larsson <[email protected]> + * + */ + +char *lookup_public_dir (void); +char *lookup_download_dir (void); |