00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifdef HAVE_CONFIG_H
00020 #include "config.h"
00021 #endif
00022
00023 #include <stdio.h>
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <dirent.h>
00027 #include <signal.h>
00028 #include <unistd.h>
00029 #include <utmp.h>
00030
00031 #include <locale.h>
00032
00033 #ifdef HAVE_CODESET
00034 #include <langinfo.h>
00035 #endif
00036
00037 #ifdef ENABLE_NOTIFY
00038 #include <sys/statvfs.h>
00039 #include <libnotify/notify.h>
00040 #endif
00041
00042 #include <gnome.h>
00043 #include <glib/gi18n.h>
00044 #include <gconf/gconf-client.h>
00045 #include <gdk/gdkx.h>
00046 #include <dbus/dbus.h>
00047 #include <dbus/dbus-glib.h>
00048 #include <dbus/dbus-glib-lowlevel.h>
00049 #include <libhal.h>
00050
00051 #include "gvm.h"
00052
00053 #ifdef GVM_DEBUG
00054 # define dbg(fmt,arg...) fprintf(stderr, "%s/%d: " fmt,__FILE__,__LINE__,##arg)
00055 #else
00056 # define dbg(fmt,arg...) do { } while(0)
00057 #endif
00058
00059 #define warn(fmt,arg...) g_warning("%s/%d: " fmt,__FILE__,__LINE__,##arg)
00060
00061 #define NAUTILUS_COMMAND "nautilus -n --no-desktop %m"
00062
00063 static struct gvm_configuration config;
00064 static DBusConnection *dbus_connection = NULL;
00065 static char *gnome_mount = NULL;
00066 static LibHalContext *hal_ctx;
00067
00068 #ifdef ENABLE_AUTOMOUNT
00069 struct _MountPolicy {
00070 char *udi;
00071 int apply;
00072 };
00073
00074
00075 static GHashTable *mount_table = NULL;
00076 static GHashTable *device_table = NULL;
00077
00078
00079 static GSList *mounted_volumes = NULL;
00080 #endif
00081
00082
00083 static GHashTable *dialogs = NULL;
00084
00085
00086 static GHashTable *statfs_mounts = NULL;
00087
00088
00089 static guint statfs_id = 0;
00090
00091
00092 typedef struct {
00093 gboolean notified;
00094 double last_notified;
00095 char *udi;
00096 } statfs_mount_info;
00097
00098 #ifdef ENABLE_NOTIFY
00099 static void statfs_mount_info_add (const char *udi);
00100 static void statfs_mount_info_remove (const char *udi);
00101 static void statfs_mount_info_free (statfs_mount_info *info);
00102 static gboolean gvm_statfs_check_space (const char *udi, statfs_mount_info *info, gpointer user_data);
00103 #endif
00104
00105 static gboolean gvm_dbus_init (void);
00106 static LibHalContext *gvm_hal_init (void);
00107
00108 static gboolean gvm_user_is_local (void);
00109 static gboolean gvm_user_is_active (void);
00110
00111
00112 typedef enum {
00113 TYPE_BOOL,
00114 TYPE_STRING,
00115 TYPE_FLOAT
00116 } type_t;
00117
00118 enum {
00119 FILEMANAGER,
00120
00121 #ifdef ENABLE_AUTOMOUNT
00122
00123 AUTOBROWSE,
00124 AUTOBURN,
00125 AUTOBURN_AUDIO_CD_COMMAND,
00126 AUTOBURN_DATA_CD_COMMAND,
00127 AUTOMOUNT_DRIVES,
00128 AUTOMOUNT_MEDIA,
00129 AUTOOPEN,
00130 AUTOOPEN_PATH,
00131 AUTORUN,
00132 AUTORUN_PATH,
00133
00134
00135 AUTOPLAY_CDA,
00136 AUTOPLAY_CDA_COMMAND,
00137 AUTOPLAY_DVD,
00138 AUTOPLAY_DVD_COMMAND,
00139 AUTOPLAY_VCD,
00140 AUTOPLAY_VCD_COMMAND,
00141 AUTOIPOD,
00142 AUTOIPOD_COMMAND,
00143 #endif
00144
00145
00146 AUTOPHOTO,
00147 AUTOPHOTO_COMMAND,
00148 AUTOVIDEOCAM,
00149 AUTOVIDEOCAM_COMMAND,
00150 AUTOWEBCAM,
00151 AUTOWEBCAM_COMMAND,
00152
00153
00154 AUTOPILOT,
00155 AUTOPILOT_COMMAND,
00156 AUTOPOCKETPC,
00157 AUTOPOCKETPC_COMMAND,
00158
00159
00160 AUTOPRINTER,
00161 AUTOPRINTER_COMMAND,
00162 AUTOSCANNER,
00163 AUTOSCANNER_COMMAND,
00164
00165
00166 AUTOKEYBOARD,
00167 AUTOKEYBOARD_COMMAND,
00168 AUTOMOUSE,
00169 AUTOMOUSE_COMMAND,
00170 AUTOTABLET,
00171 AUTOTABLET_COMMAND,
00172
00173
00174 PERCENT_THRESHOLD,
00175 PERCENT_FREED,
00176 PERCENT_USED
00177 };
00178
00179 static struct {
00180 char *key;
00181 type_t type;
00182 void *var;
00183 } gvm_settings[] = {
00184 { GCONF_ROOT "filemanager", TYPE_STRING, &config.filemanager },
00185 #ifdef ENABLE_AUTOMOUNT
00186
00187 { GCONF_ROOT "autobrowse", TYPE_BOOL, &config.autobrowse },
00188 { GCONF_ROOT "autoburn", TYPE_BOOL, &config.autoburn },
00189 { GCONF_ROOT "autoburn_audio_cd_command", TYPE_STRING, &config.autoburn_audio_cd_command },
00190 { GCONF_ROOT "autoburn_data_cd_command", TYPE_STRING, &config.autoburn_data_cd_command },
00191 { GCONF_ROOT "automount_drives", TYPE_BOOL, &config.automount_drives },
00192 { GCONF_ROOT "automount_media", TYPE_BOOL, &config.automount_media },
00193 { GCONF_ROOT "autoopen", TYPE_BOOL, &config.autoopen },
00194 { GCONF_ROOT "autoopen_path", TYPE_STRING, &config.autoopen_path },
00195 { GCONF_ROOT "autorun", TYPE_BOOL, &config.autorun },
00196 { GCONF_ROOT "autorun_path", TYPE_STRING, &config.autorun_path },
00197
00198
00199 { GCONF_ROOT "autoplay_cda", TYPE_BOOL, &config.autoplay_cda },
00200 { GCONF_ROOT "autoplay_cda_command", TYPE_STRING, &config.autoplay_cda_command },
00201 { GCONF_ROOT "autoplay_dvd", TYPE_BOOL, &config.autoplay_dvd },
00202 { GCONF_ROOT "autoplay_dvd_command", TYPE_STRING, &config.autoplay_dvd_command },
00203 { GCONF_ROOT "autoplay_vcd", TYPE_BOOL, &config.autoplay_vcd },
00204 { GCONF_ROOT "autoplay_vcd_command", TYPE_STRING, &config.autoplay_vcd_command },
00205 { GCONF_ROOT "autoipod", TYPE_BOOL, &config.autoipod },
00206 { GCONF_ROOT "autoipod_command", TYPE_STRING, &config.autoipod_command },
00207 #endif
00208
00209
00210 { GCONF_ROOT "autophoto", TYPE_BOOL, &config.autophoto },
00211 { GCONF_ROOT "autophoto_command", TYPE_STRING, &config.autophoto_command },
00212 { GCONF_ROOT "autovideocam", TYPE_BOOL, &config.autovideocam },
00213 { GCONF_ROOT "autovideocam_command", TYPE_STRING, &config.autovideocam_command },
00214 { GCONF_ROOT "autowebcam", TYPE_BOOL, &config.autowebcam },
00215 { GCONF_ROOT "autowebcam_command", TYPE_STRING, &config.autowebcam_command },
00216
00217
00218 { GCONF_ROOT "autopalmsync", TYPE_BOOL, &config.autopilot },
00219 { GCONF_ROOT "autopalmsync_command", TYPE_STRING, &config.autopilot_command },
00220 { GCONF_ROOT "autopocketpc", TYPE_BOOL, &config.autopocketpc },
00221 { GCONF_ROOT "autopocketpc_command", TYPE_STRING, &config.autopocketpc_command },
00222
00223
00224 { GCONF_ROOT "autoprinter", TYPE_BOOL, &config.autoprinter },
00225 { GCONF_ROOT "autoprinter_command", TYPE_STRING, &config.autoprinter_command },
00226 { GCONF_ROOT "autoscanner", TYPE_BOOL, &config.autoscanner },
00227 { GCONF_ROOT "autoscanner_command", TYPE_STRING, &config.autoscanner_command },
00228
00229
00230 { GCONF_ROOT "autokeyboard", TYPE_BOOL, &config.autokeyboard },
00231 { GCONF_ROOT "autokeyboard_command", TYPE_STRING, &config.autokeyboard_command },
00232 { GCONF_ROOT "automouse", TYPE_BOOL, &config.automouse },
00233 { GCONF_ROOT "automouse_command", TYPE_STRING, &config.automouse_command },
00234 { GCONF_ROOT "autotablet", TYPE_BOOL, &config.autotablet },
00235 { GCONF_ROOT "autotablet_command", TYPE_STRING, &config.autotablet_command },
00236
00237
00238 { GCONF_ROOT "percent_threshold", TYPE_FLOAT, &config.percent_threshold },
00239 { GCONF_ROOT "percent_used", TYPE_FLOAT, &config.percent_used },
00240 };
00241
00242 static GHashTable *gvm_settings_hash = NULL;
00243
00244
00245 struct _GvmPromptButton {
00246 const char *label;
00247 const char *stock;
00248 int response_id;
00249 };
00250
00251 enum {
00252 GVM_RESPONSE_NONE,
00253 GVM_RESPONSE_RUN,
00254 GVM_RESPONSE_OPEN,
00255 GVM_RESPONSE_PLAY,
00256 GVM_RESPONSE_BROWSE,
00257 GVM_RESPONSE_SYNC_MUSIC,
00258 GVM_RESPONSE_IMPORT_PHOTOS,
00259 GVM_RESPONSE_WRITE_AUDIO_CD,
00260 GVM_RESPONSE_WRITE_DATA_CD,
00261 };
00262
00263 static struct _GvmPromptButton GVM_BUTTONS_AUTORUN[] = {
00264 { N_("Ig_nore"), NULL, GTK_RESPONSE_CANCEL },
00265 { N_("_Allow Auto-Run"), NULL, GVM_RESPONSE_RUN },
00266 };
00267
00268 static struct _GvmPromptButton GVM_BUTTONS_AUTOOPEN[] = {
00269 { N_("Ig_nore"), NULL, GTK_RESPONSE_CANCEL },
00270 { N_("_Open"), NULL, GVM_RESPONSE_OPEN },
00271 };
00272
00273 static struct _GvmPromptButton GVM_BUTTONS_CAMERA[] = {
00274 { N_("Ig_nore"), NULL, GTK_RESPONSE_CANCEL },
00275 { N_("Import _Photos"), NULL, GVM_RESPONSE_IMPORT_PHOTOS },
00276 };
00277
00278 static struct _GvmPromptButton GVM_BUTTONS_STORAGE_CAMERA[] = {
00279 { N_("Ig_nore"), NULL, GTK_RESPONSE_CANCEL },
00280 { N_("_Open Folder"), NULL, GVM_RESPONSE_BROWSE },
00281 { N_("Import _Photos"), NULL, GVM_RESPONSE_IMPORT_PHOTOS },
00282 };
00283
00284 static struct _GvmPromptButton GVM_BUTTONS_IPOD_PHOTO[] = {
00285 { N_("Ig_nore"), NULL, GTK_RESPONSE_CANCEL },
00286 { N_("Import _Photos"), NULL, GVM_RESPONSE_IMPORT_PHOTOS },
00287 { N_("Manage _Music"), NULL, GVM_RESPONSE_SYNC_MUSIC },
00288 };
00289
00290 static struct _GvmPromptButton GVM_BUTTONS_MIXED_CD[] = {
00291 { N_("Ig_nore"), NULL, GTK_RESPONSE_CANCEL },
00292 { N_("_Browse Files"), NULL, GVM_RESPONSE_BROWSE },
00293 { N_("_Play CD"), NULL, GVM_RESPONSE_PLAY },
00294 };
00295
00296 static struct _GvmPromptButton GVM_BUTTONS_WRITE_CD[] = {
00297 { N_("Ig_nore"), NULL, GTK_RESPONSE_CANCEL },
00298 { N_("Make _Audio CD"), NULL, GVM_RESPONSE_WRITE_AUDIO_CD },
00299 { N_("Make _Data CD"), NULL, GVM_RESPONSE_WRITE_DATA_CD },
00300 };
00301
00302 static struct _GvmPromptButton GVM_BUTTONS_WRITE_DVD[] = {
00303 { N_("Ig_nore"), NULL, GTK_RESPONSE_CANCEL },
00304 { N_("Make _DVD"), NULL, GVM_RESPONSE_WRITE_DATA_CD },
00305 };
00306
00307 typedef enum {
00308 GVM_PROMPT_AUTORUN,
00309 GVM_PROMPT_AUTOOPEN,
00310 GVM_PROMPT_IMPORT_CAMERA,
00311 GVM_PROMPT_IMPORT_STORAGE_CAMERA,
00312 GVM_PROMPT_IMPORT_PHOTOS,
00313 GVM_PROMPT_IPOD_PHOTO,
00314 GVM_PROMPT_CDA_EXTRA,
00315 GVM_PROMPT_WRITE_CDR,
00316 GVM_PROMPT_WRITE_DVD,
00317 } GvmPrompt;
00318
00319 typedef struct _GvmPromptCtx GvmPromptCtx;
00320 typedef void (* GvmPromptCallback) (GvmPromptCtx *ctx, int action);
00321
00322 struct _GvmPromptCtx {
00323 GvmPrompt prompt;
00324
00325 GvmPromptCallback callback;
00326
00327 char *udi;
00328 char *device;
00329 char *mount_point;
00330 char *path;
00331 };
00332
00333 static struct {
00334 GtkDialogFlags flags;
00335
00336 const char *icon;
00337
00338 const char *help_uri;
00339
00340 struct _GvmPromptButton *buttons;
00341 int n_buttons;
00342
00343 int default_response;
00344
00345 const char *title;
00346 const char *primary;
00347 const char *secondary;
00348 int secondary_has_args;
00349 int secondary_has_mockup;
00350
00351 const char *ask_again_key;
00352 const char *ask_again_label;
00353 } gvm_prompts[] = {
00354 { 0, "gnome-fs-executable", NULL,
00355 GVM_BUTTONS_AUTORUN, G_N_ELEMENTS (GVM_BUTTONS_AUTORUN),
00356 GVM_RESPONSE_RUN,
00357 N_("Auto-Run Confirmation"),
00358 N_("Auto-run capability detected."),
00359 N_("Would you like to allow <b>'${0}'</b> to run?"), TRUE, TRUE,
00360 NULL, NULL },
00361 { 0, "gnome-fs-executable", NULL,
00362 GVM_BUTTONS_AUTOOPEN, G_N_ELEMENTS (GVM_BUTTONS_AUTOOPEN),
00363 GVM_RESPONSE_RUN,
00364 N_("Auto-Open Confirmation"),
00365 N_("Auto-Open capability detected."),
00366 N_("Would you like to open <b>'${0}'</b>?"), TRUE, TRUE,
00367 NULL, NULL },
00368 { 0, "camera-photo", NULL,
00369 GVM_BUTTONS_CAMERA, G_N_ELEMENTS (GVM_BUTTONS_CAMERA),
00370 GVM_RESPONSE_IMPORT_PHOTOS,
00371 N_("Camera Import"),
00372 N_("A camera has been detected."),
00373 N_("There are photos on the camera. Would you like to add these pictures to your album?"), FALSE, FALSE,
00374 GCONF_ROOT "prompts/camera_import_photos", N_("_Always perform this action") },
00375 { 0, "camera-photo", NULL,
00376 GVM_BUTTONS_STORAGE_CAMERA, G_N_ELEMENTS (GVM_BUTTONS_STORAGE_CAMERA),
00377 GVM_RESPONSE_IMPORT_PHOTOS,
00378 N_("Camera Import"),
00379 N_("A camera has been detected."),
00380 N_("There are photos on the camera. Would you like to add these pictures to your album?"), FALSE, FALSE,
00381 GCONF_ROOT "prompts/storage_camera_import_photos", N_("_Always perform this action") },
00382 { 0, "camera-photo", NULL,
00383 GVM_BUTTONS_CAMERA, G_N_ELEMENTS (GVM_BUTTONS_CAMERA),
00384 GVM_RESPONSE_IMPORT_PHOTOS,
00385 N_("Photo Import"),
00386 N_("A photo card has been detected."),
00387 N_("There are photos on the card. Would you like to add these pictures to your album?"), FALSE, FALSE,
00388 GCONF_ROOT "prompts/device_import_photos", N_("_Always perform this action") },
00389 { 0, "gnome-dev-ipod", NULL,
00390 GVM_BUTTONS_IPOD_PHOTO, G_N_ELEMENTS (GVM_BUTTONS_IPOD_PHOTO),
00391 GVM_RESPONSE_SYNC_MUSIC,
00392 N_("Photos and Music"),
00393 N_("Photos were found on your music device."),
00394 N_("Would you like to import the photos or manage its music?"), FALSE, FALSE,
00395 GCONF_ROOT "prompts/ipod_photo", N_("_Always perform this action") },
00396 { 0, "gnome-dev-cdrom-audio", NULL,
00397 GVM_BUTTONS_MIXED_CD, G_N_ELEMENTS (GVM_BUTTONS_MIXED_CD),
00398 GVM_RESPONSE_PLAY,
00399 N_("Mixed Audio and Data CD"),
00400 N_("The CD in the drive contains both music and files."),
00401 N_("Would you like to listen to music or browse the files?"), FALSE, FALSE,
00402 GCONF_ROOT "prompts/cd_mixed", N_("_Always perform this action") },
00403 { 0, "gnome-dev-cdrom", NULL,
00404 GVM_BUTTONS_WRITE_CD, G_N_ELEMENTS (GVM_BUTTONS_WRITE_CD),
00405 GVM_RESPONSE_WRITE_DATA_CD,
00406 N_("Blank CD Inserted"),
00407 N_("You have inserted a blank disc."),
00408 N_("What would you like to do?"), FALSE, FALSE,
00409 NULL, NULL },
00410 { 0, "gnome-dev-disc-dvdr", NULL,
00411 GVM_BUTTONS_WRITE_DVD, G_N_ELEMENTS (GVM_BUTTONS_WRITE_DVD),
00412 GVM_RESPONSE_WRITE_DATA_CD,
00413 N_("Blank DVD Inserted"),
00414 N_("You have inserted a blank disc."),
00415 N_("What would you like to do?"), FALSE, FALSE,
00416 NULL, NULL },
00417 };
00418
00419
00420 static GvmPromptCtx *
00421 gvm_prompt_ctx_new (GvmPrompt prompt, GvmPromptCallback callback, const char *udi,
00422 const char *device, const char *mount_point, const char *path)
00423 {
00424 GvmPromptCtx *ctx;
00425
00426 ctx = g_malloc (sizeof (GvmPromptCtx));
00427 ctx->prompt = prompt;
00428 ctx->callback = callback;
00429 ctx->udi = g_strdup (udi);
00430 ctx->device = g_strdup (device);
00431 ctx->mount_point = g_strdup (mount_point);
00432 ctx->path = g_strdup (path);
00433
00434 return ctx;
00435 }
00436
00437 static void
00438 gvm_prompt_ctx_free (GvmPromptCtx *ctx)
00439 {
00440 g_free (ctx->udi);
00441 g_free (ctx->device);
00442 g_free (ctx->mount_point);
00443 g_free (ctx->path);
00444 g_free (ctx);
00445 }
00446
00447 static void
00448 prompt_response_cb (GtkWidget *dialog, int response, GvmPromptCtx *ctx)
00449 {
00450 GtkToggleButton *checkbox;
00451 GConfClient *gconf;
00452 GError *err = NULL;
00453
00454 if (response == GTK_RESPONSE_HELP) {
00455 g_signal_stop_emission_by_name (dialog, "response");
00456 gnome_url_show (gvm_prompts[ctx->prompt].help_uri, &err);
00457 if (err) {
00458 warn ("Unable to run help uri: %s", err->message);
00459 g_error_free (err);
00460 }
00461
00462 return;
00463 }
00464
00465 checkbox = g_object_get_data ((GObject *) dialog, "checkbox");
00466 if (checkbox && gtk_toggle_button_get_active (checkbox) && response != GTK_RESPONSE_CANCEL) {
00467 gconf = gconf_client_get_default ();
00468 gconf_client_set_int (gconf, gvm_prompts[ctx->prompt].ask_again_key, response, NULL);
00469 g_object_unref (gconf);
00470 }
00471
00472 g_hash_table_remove (dialogs, ctx->udi);
00473 ctx->callback (ctx, response);
00474 gtk_widget_destroy (dialog);
00475 gvm_prompt_ctx_free (ctx);
00476 }
00477
00478 static char *
00479 argv_expand (const char *format, int argc, char **argv)
00480 {
00481 const char *start, *inptr;
00482 GString *string;
00483 char *str;
00484 int i;
00485
00486 string = g_string_new ("");
00487 start = inptr = format;
00488
00489 while (*inptr) {
00490 while (*inptr) {
00491 if (inptr[0] == '$' && inptr[1] == '{' && inptr[2] >= '0' && inptr[2] <= '9')
00492 break;
00493 inptr++;
00494 }
00495
00496 if (*inptr == '\0')
00497 break;
00498
00499 g_string_append_len (string, start, inptr - start);
00500
00501 start = inptr;
00502 inptr += 2;
00503 i = strtol (inptr, &str, 10);
00504 if (*str == '}' && i < argc) {
00505 start = inptr = str + 1;
00506 g_string_append (string, argv[i]);
00507 }
00508 }
00509
00510 g_string_append (string, start);
00511
00512 str = string->str;
00513 g_string_free (string, FALSE);
00514
00515 return str;
00516 }
00517
00518 static void
00519 gvm_prompt (GvmPromptCtx *ctx, int argc, char **argv)
00520 {
00521 GtkWidget *dialog, *hbox, *vbox, *image, *label, *check = NULL;
00522 GvmPrompt prompt = ctx->prompt;
00523 GConfClient *gconf;
00524 GError *err = NULL;
00525 const char *text;
00526 int response, i;
00527 char *buf;
00528
00529 gconf = gconf_client_get_default ();
00530
00531
00532 if (gvm_prompts[prompt].ask_again_key) {
00533 response = gconf_client_get_int (gconf, gvm_prompts[prompt].ask_again_key, &err);
00534 if (response > GVM_RESPONSE_NONE && err == NULL) {
00535 ctx->callback (ctx, response);
00536 return;
00537 }
00538
00539 if (err != NULL)
00540 g_error_free (err);
00541 }
00542
00543 dialog = gtk_dialog_new ();
00544 gtk_widget_ensure_style (dialog);
00545 gtk_dialog_set_has_separator ((GtkDialog *) dialog, FALSE);
00546
00547 gtk_container_set_border_width ((GtkContainer *) ((GtkDialog *) dialog)->vbox, 0);
00548 gtk_container_set_border_width ((GtkContainer *) ((GtkDialog *) dialog)->action_area, 12);
00549
00550 if (gvm_prompts[prompt].title)
00551 gtk_window_set_title ((GtkWindow *) dialog, _(gvm_prompts[prompt].title));
00552
00553 if (gvm_prompts[prompt].flags & GTK_DIALOG_MODAL)
00554 gtk_window_set_modal ((GtkWindow *) dialog, TRUE);
00555
00556 if (gvm_prompts[prompt].help_uri)
00557 gtk_dialog_add_button ((GtkDialog *) dialog, GTK_STOCK_HELP, GTK_RESPONSE_HELP);
00558
00559 if (gvm_prompts[prompt].buttons) {
00560 for (i = 0; i < gvm_prompts[prompt].n_buttons; i++) {
00561 const char *name;
00562
00563 name = gvm_prompts[prompt].buttons[i].stock ?
00564 gvm_prompts[prompt].buttons[i].stock :
00565 _(gvm_prompts[prompt].buttons[i].label);
00566
00567 gtk_dialog_add_button ((GtkDialog *) dialog, name, gvm_prompts[prompt].buttons[i].response_id);
00568 }
00569
00570 if (gvm_prompts[prompt].default_response != GVM_RESPONSE_NONE)
00571 gtk_dialog_set_default_response ((GtkDialog *) dialog, gvm_prompts[prompt].default_response);
00572 } else {
00573 gtk_dialog_add_button ((GtkDialog *) dialog, GTK_STOCK_OK, GTK_RESPONSE_OK);
00574 }
00575
00576 hbox = gtk_hbox_new (FALSE, 0);
00577 gtk_container_set_border_width ((GtkContainer *) hbox, 12);
00578
00579
00580 image = gtk_image_new_from_icon_name (gvm_prompts[prompt].icon, GTK_ICON_SIZE_DIALOG);
00581
00582 gtk_misc_set_alignment ((GtkMisc *) image, 0.0, 0.0);
00583 gtk_box_pack_start ((GtkBox *) hbox, image, FALSE, FALSE, 12);
00584 gtk_widget_show (image);
00585
00586 vbox = gtk_vbox_new (FALSE, 0);
00587 gtk_box_pack_start ((GtkBox *) hbox, vbox, FALSE, FALSE, 0);
00588
00589
00590 buf = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>", _(gvm_prompts[prompt].primary));
00591
00592 label = gtk_label_new (NULL);
00593 gtk_misc_set_alignment ((GtkMisc *) label, 0.0, 0.5);
00594 gtk_label_set_line_wrap ((GtkLabel *) label, FALSE);
00595 gtk_label_set_markup ((GtkLabel *) label, buf);
00596 g_free (buf);
00597
00598 gtk_box_pack_start ((GtkBox *) vbox, label, FALSE, FALSE, 0);
00599 gtk_widget_show (label);
00600
00601
00602 buf = NULL;
00603 if (gvm_prompts[prompt].secondary_has_args) {
00604 text = buf = argv_expand (_(gvm_prompts[prompt].secondary), argc, argv);
00605 } else {
00606 text = _(gvm_prompts[prompt].secondary);
00607 }
00608
00609 label = gtk_label_new (NULL);
00610 gtk_misc_set_alignment ((GtkMisc *) label, 0.0, 0.5);
00611
00612 gtk_label_set_line_wrap ((GtkLabel *) label, TRUE);
00613 if (gvm_prompts[prompt].secondary_has_mockup)
00614 gtk_label_set_markup ((GtkLabel *) label, text);
00615 else
00616 gtk_label_set_text ((GtkLabel *) label, text);
00617 g_free (buf);
00618
00619 gtk_box_pack_start ((GtkBox *) vbox, label, FALSE, FALSE, 6);
00620 gtk_widget_show (label);
00621
00622 gtk_box_pack_start ((GtkBox *) ((GtkDialog *) dialog)->vbox, hbox, FALSE, FALSE, 0);
00623
00624
00625 if (gvm_prompts[prompt].ask_again_key && gvm_prompts[prompt].ask_again_label) {
00626 check = gtk_check_button_new_with_mnemonic (_(gvm_prompts[prompt].ask_again_label));
00627 gtk_container_set_border_width ((GtkContainer *) check, 0);
00628 gtk_box_pack_start ((GtkBox *) vbox, check, FALSE, FALSE, 0);
00629 g_object_set_data ((GObject *) dialog, "checkbox", check);
00630 gtk_widget_show (check);
00631 }
00632
00633 gtk_widget_show (vbox);
00634 gtk_widget_show (hbox);
00635
00636 g_object_unref (gconf);
00637
00638 g_hash_table_insert (dialogs, ctx->udi, dialog);
00639
00640 g_signal_connect (dialog, "response", G_CALLBACK (prompt_response_cb), ctx);
00641
00642 gtk_widget_show (dialog);
00643 }
00644
00645 static void
00646 to_be_or_not_to_be (void)
00647 {
00648
00649
00650
00651
00652
00653 gboolean live = FALSE;
00654 size_t i;
00655
00656
00657 for (i = 0; i < G_N_ELEMENTS (gvm_settings) && !live; i++) {
00658 if (gvm_settings[i].type == TYPE_BOOL)
00659 live = *((int *) gvm_settings[i].var);
00660 }
00661
00662
00663 if (!live) {
00664 dbg ("daemon exit: live and let die\n");
00665 exit (EXIT_SUCCESS);
00666 }
00667 }
00668
00669
00670
00671
00672 static void
00673 gvm_load_config (void)
00674 {
00675 size_t i;
00676
00677 gvm_settings_hash = g_hash_table_new (g_str_hash, g_str_equal);
00678
00679 for (i = 0; i < G_N_ELEMENTS (gvm_settings); i++) {
00680 g_hash_table_insert (gvm_settings_hash, gvm_settings[i].key, GINT_TO_POINTER (i + 1));
00681 if (gvm_settings[i].type == TYPE_STRING) {
00682 *((char **) gvm_settings[i].var) =
00683 gconf_client_get_string (config.client, gvm_settings[i].key, NULL);
00684 dbg ("setting[%d]: string: %s = %s\n", i, strrchr (gvm_settings[i].key, '/') + 1,
00685 *((char **) gvm_settings[i].var) ? *((char **) gvm_settings[i].var): "NULL");
00686 } else if (gvm_settings[i].type == TYPE_BOOL) {
00687 *((int *) gvm_settings[i].var) =
00688 gconf_client_get_bool (config.client, gvm_settings[i].key, NULL);
00689 dbg ("setting[%d]: bool: %s = %d\n", i, strrchr (gvm_settings[i].key, '/') + 1,
00690 *((int *) gvm_settings[i].var));
00691 } else if (gvm_settings[i].type == TYPE_FLOAT) {
00692 *((double *) gvm_settings[i].var) =
00693 gconf_client_get_float (config.client, gvm_settings[i].key, NULL);
00694 if (*((double *) gvm_settings[i].var) >= 1.0)
00695 *((double *) gvm_settings[i].var) = 1.0;
00696 else if (*((double *) gvm_settings[i].var) <= 0.0)
00697 *((double *) gvm_settings[i].var) = 0.0;
00698 dbg ("settings[%d]: float: %s = %f\n", i, strrchr (gvm_settings[i].key, '/') + 1,
00699 *((double *) gvm_settings[i].var));
00700 } else {
00701 g_assert_not_reached ();
00702 }
00703 }
00704
00705 to_be_or_not_to_be ();
00706 }
00707
00708
00709
00710
00711 static void
00712 gvm_config_changed (GConfClient *client GNUC_UNUSED,
00713 guint id GNUC_UNUSED,
00714 GConfEntry *entry,
00715 gpointer data GNUC_UNUSED)
00716 {
00717 GConfValue *value;
00718 gpointer result;
00719 int which;
00720
00721 g_return_if_fail (gconf_entry_get_key (entry) != NULL);
00722
00723 if (!(value = gconf_entry_get_value (entry)))
00724 return;
00725
00726 if (!(result = g_hash_table_lookup (gvm_settings_hash, entry->key)))
00727 return;
00728
00729 which = GPOINTER_TO_INT (result) - 1;
00730
00731 if (gvm_settings[which].type == TYPE_STRING) {
00732 g_free (*((char **) gvm_settings[which].var));
00733 *((char **) gvm_settings[which].var) = g_strdup (gconf_value_get_string (value));
00734 dbg ("setting changed: string: %s = %s\n", strrchr (gvm_settings[which].key, '/') + 1,
00735 *((char **) gvm_settings[which].var));
00736 } else if (gvm_settings[which].type == TYPE_BOOL) {
00737 *((int *) gvm_settings[which].var) = gconf_value_get_bool (value);
00738 dbg ("setting changed: bool: %s = %d\n", strrchr (gvm_settings[which].key, '/') + 1,
00739 *((int *) gvm_settings[which].var));
00740 } else if (gvm_settings[which].type == TYPE_FLOAT) {
00741 *((double *) gvm_settings[which].var) = gconf_client_get_float (config.client, gvm_settings[which].key, NULL);
00742 if (*((double *) gvm_settings[which].var) >= 1.0)
00743 *((double *) gvm_settings[which].var) = 1.0;
00744 else if (*((double *) gvm_settings[which].var) <= 0.0)
00745 *((double *) gvm_settings[which].var) = 0.0;
00746 dbg ("settings[%d]: float: %s = %f\n", which, strrchr (gvm_settings[which].key, '/') + 1,
00747 *((double *) gvm_settings[which].var));
00748 } else {
00749 g_assert_not_reached ();
00750 }
00751
00752 to_be_or_not_to_be ();
00753 }
00754
00755
00756
00757
00758 static void
00759 gvm_init_config (void)
00760 {
00761 config.client = gconf_client_get_default ();
00762
00763 gconf_client_add_dir (config.client, GCONF_ROOT_SANS_SLASH,
00764 GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
00765
00766 gvm_load_config ();
00767
00768 gconf_client_notify_add (config.client, GCONF_ROOT_SANS_SLASH,
00769 gvm_config_changed, NULL, NULL, NULL);
00770 }
00771
00772
00773
00774
00775
00776
00777
00778 static gboolean
00779 gvm_run_command (const char *command, const char *udi, const char *device, const char *mount_point)
00780 {
00781 char *path, *mp = NULL, *dev = NULL;
00782 const char *inptr, *start;
00783 GError *error = NULL;
00784 GString *exec;
00785 char *argv[4];
00786
00787 g_assert (udi != NULL);
00788
00789 exec = g_string_new (NULL);
00790
00791
00792 start = inptr = command;
00793 while ((inptr = strchr (inptr, '%')) != NULL) {
00794 g_string_append_len (exec, start, inptr - start);
00795 inptr++;
00796 switch (*inptr) {
00797 case 'd':
00798 g_string_append (exec, device ? device : "");
00799 break;
00800 case 'm':
00801 if (mount_point == NULL && libhal_device_query_capability (hal_ctx, udi, "volume", NULL)) {
00802 mp = libhal_device_get_property_string (hal_ctx, udi, "volume.mount_point", NULL);
00803 mount_point = mp;
00804 }
00805
00806 if (mount_point) {
00807 path = g_shell_quote (mount_point);
00808 g_string_append (exec, path);
00809 g_free (path);
00810 } else {
00811 g_string_append (exec, "\"\"");
00812 }
00813 break;
00814 case 'h':
00815 g_string_append (exec, udi);
00816 break;
00817 case '%':
00818 g_string_append_c (exec, '%');
00819 break;
00820 default:
00821 g_string_append_c (exec, '%');
00822 if (*inptr)
00823 g_string_append_c (exec, *inptr);
00824 break;
00825 }
00826
00827 if (*inptr)
00828 inptr++;
00829 start = inptr;
00830 }
00831 g_string_append (exec, start);
00832
00833 libhal_free_string (mp);
00834 libhal_free_string (dev);
00835
00836 argv[0] = "/bin/sh";
00837 argv[1] = "-c";
00838 argv[2] = exec->str;
00839 argv[3] = NULL;
00840
00841 dbg ("executing command: %s\n", exec->str);
00842 if (!g_spawn_async (g_get_home_dir (), argv, NULL, 0, NULL, NULL, NULL, &error)) {
00843 warn ("failed to exec %s: %s", exec->str, error->message);
00844 g_string_free (exec, TRUE);
00845 g_error_free (error);
00846 return FALSE;
00847 }
00848
00849 g_string_free (exec, TRUE);
00850
00851 return TRUE;
00852 }
00853
00854 static gboolean
00855 gvm_check_dir (const char *dirname, const char *name, gboolean check_contents)
00856 {
00857 gboolean exists = FALSE;
00858 struct dirent *dent;
00859 char *path = NULL;
00860 struct stat st;
00861 DIR *dir;
00862
00863 if (!(dir = opendir (dirname)))
00864 return FALSE;
00865
00866 while ((dent = readdir (dir))) {
00867 if (!g_ascii_strcasecmp (dent->d_name, name)) {
00868 path = g_build_filename (dirname, dent->d_name, NULL);
00869 if (stat (path, &st) == 0 && S_ISDIR (st.st_mode))
00870 exists = TRUE;
00871 break;
00872 }
00873 }
00874
00875 closedir (dir);
00876
00877 if (exists && check_contents) {
00878 exists = FALSE;
00879 if ((dir = opendir (path))) {
00880 while ((dent = readdir (dir))) {
00881 if (!strcmp (dent->d_name, "..")
00882 || !strcmp (dent->d_name, "."))
00883 continue;
00884
00885 exists = TRUE;
00886 break;
00887 }
00888
00889 closedir (dir);
00890 }
00891 }
00892
00893 g_free (path);
00894
00895 return exists;
00896 }
00897
00898 #ifdef ENABLE_AUTOMOUNT
00899
00900
00901
00902
00903
00904 static gboolean
00905 gvm_check_dvd (const char *udi, const char *device, const char *mount_point)
00906 {
00907 gboolean is_dvd;
00908
00909 is_dvd = gvm_check_dir (mount_point, "video_ts", FALSE);
00910
00911 if (is_dvd && config.autoplay_dvd)
00912 gvm_run_command (config.autoplay_dvd_command, udi, device, mount_point);
00913
00914 return is_dvd;
00915 }
00916
00917
00918
00919
00920
00921
00922 static gboolean
00923 gvm_check_vcd (const char *udi, const char *device, const char *mount_point)
00924 {
00925 gboolean is_vcd;
00926
00927 is_vcd = gvm_check_dir (mount_point, "vcd", FALSE);
00928
00929 if (is_vcd && config.autoplay_vcd)
00930 gvm_run_command (config.autoplay_vcd_command, udi, device, mount_point);
00931
00932 return is_vcd;
00933 }
00934 #endif
00935
00936
00937
00938
00939
00940
00941 static gboolean
00942 gvm_udi_is_storage_camera (const char *udi)
00943 {
00944 char *physical_device = NULL;
00945 char *storage_device = NULL;
00946 gboolean is_camera = FALSE;
00947 DBusError error;
00948
00949 dbus_error_init (&error);
00950 if (!(storage_device = libhal_device_get_property_string (hal_ctx, udi, "block.storage_device", &error))) {
00951 warn ("cannot get block.storage_device property: %s", error.message);
00952 if (dbus_error_is_set (&error))
00953 dbus_error_free (&error);
00954 return FALSE;
00955 }
00956
00957 if (!(physical_device = libhal_device_get_property_string (hal_ctx, storage_device, "storage.physical_device", &error))) {
00958 warn ("cannot get storage.physical_device property: %s", error.message);
00959 if (dbus_error_is_set (&error))
00960 dbus_error_free (&error);
00961 goto out;
00962 }
00963
00964 if ((is_camera = libhal_device_query_capability (hal_ctx, physical_device, "camera", NULL)))
00965 dbg ("Camera detected: %s\n", udi);
00966
00967 out:
00968
00969 libhal_free_string (storage_device);
00970 libhal_free_string (physical_device);
00971
00972 return is_camera;
00973 }
00974
00975
00976
00977
00978
00979
00980 static gboolean
00981 gvm_udi_is_camera (const char *udi)
00982 {
00983 gboolean is_camera = FALSE;
00984 char *access_method;
00985 char *driver;
00986
00987 #if 0
00988
00989 if (!libhal_device_query_capability (hal_ctx, udi, "camera", NULL))
00990 return FALSE;
00991 #endif
00992
00993 if (!(access_method = libhal_device_get_property_string (hal_ctx, udi, "camera.access_method", NULL)))
00994 return FALSE;
00995
00996 if (!strcmp (access_method, "storage")) {
00997
00998 is_camera = FALSE;
00999 goto done;
01000 } else if (!strcmp (access_method, "ptp")) {
01001
01002 is_camera = TRUE;
01003 goto done;
01004 } else if (!strcmp (access_method, "libgphoto2")) {
01005
01006 warn ("Please update your libgphoto2 package as the fdi files are outdated!\n");
01007 if ((driver = libhal_device_get_property_string (hal_ctx, udi, "info.linux.driver", NULL))) {
01008
01009
01010 if (!strcmp (driver, "usb-storage"))
01011 is_camera = FALSE;
01012 } else {
01013 is_camera = TRUE;
01014 }
01015
01016 libhal_free_string (driver);
01017
01018 goto done;
01019 }
01020
01021 dbg ("Non Mass-Storage Camera detected: %s\n", udi);
01022
01023 is_camera = libhal_device_get_property_bool (hal_ctx, udi, "camera.libgphoto2.support", NULL);
01024
01025 done:
01026
01027 libhal_free_string (access_method);
01028
01029 return is_camera;
01030 }
01031
01032 #if 0
01033
01034
01035
01036
01037
01038 static gboolean
01039 gvm_udi_is_ipod (const char *udi)
01040 {
01041 char *storage_device = NULL;
01042 gboolean is_ipod = FALSE;
01043 char *product = NULL;
01044 DBusError error;
01045
01046 dbus_error_init (&error);
01047 if (!(storage_device = libhal_device_get_property_string (hal_ctx, udi, "block.storage_device", &error))) {
01048 warn ("cannot get block.storage_device property: %s", error.message);
01049 if (dbus_error_is_set (&error))
01050 dbus_error_free (&error);
01051 return FALSE;
01052 }
01053
01054 if (!(product = libhal_device_get_property_string (hal_ctx, storage_device, "info.product", &error))) {
01055 warn ("cannot get info.product property: %s", error.message);
01056 if (dbus_error_is_set (&error))
01057 dbus_error_free (&error);
01058 goto out;
01059 }
01060
01061 if ((is_ipod = !strcmp (product, "iPod")))
01062 dbg ("iPod detected: %s\n", udi);
01063 else
01064 dbg ("not an iPod: %s\n", udi);
01065
01066 out:
01067
01068 libhal_free_string (storage_device);
01069 libhal_free_string (product);
01070
01071 return is_ipod;
01072 }
01073 #endif
01074
01075 #ifdef ENABLE_AUTOMOUNT
01076
01077
01078
01079
01080
01081 static gboolean
01082 gvm_udi_is_portable_media_player (const char *udi, gboolean *is_ipod)
01083 {
01084 char *storage_device = NULL;
01085 gboolean is_player = FALSE;
01086 char *product = NULL;
01087 DBusError error;
01088
01089 if (is_ipod)
01090 *is_ipod = FALSE;
01091
01092 dbus_error_init (&error);
01093 if (!(storage_device = libhal_device_get_property_string (hal_ctx, udi, "block.storage_device", &error))) {
01094 warn ("cannot get block.storage_device property: %s", error.message);
01095 if (dbus_error_is_set (&error))
01096 dbus_error_free (&error);
01097 return FALSE;
01098 }
01099
01100 if (is_ipod && (product = libhal_device_get_property_string (hal_ctx, storage_device, "info.product", NULL))) {
01101 *is_ipod = !strcmp (product, "iPod");
01102 libhal_free_string (product);
01103 }
01104
01105 if ((is_player = libhal_device_query_capability (hal_ctx, storage_device, "portable_audio_player", NULL)))
01106 dbg ("%s detected: %s\n", is_ipod && *is_ipod ? "iPod" : "Generic music player", udi);
01107
01108 libhal_free_string (storage_device);
01109
01110 return is_player;
01111 }
01112 #endif
01113
01114
01115
01116
01117 static void
01118 gvm_run_camera (const char *udi, const char *device, const char *mount_point)
01119 {
01120 if (config.autophoto_command != NULL)
01121 gvm_run_command (config.autophoto_command, udi, device, mount_point);
01122 }
01123
01124
01125
01126
01127
01128
01129 static gboolean
01130 gvm_check_photos (const char *udi, const char *device, const char *mount_point)
01131 {
01132 DBusError error;
01133
01134 if (!gvm_check_dir (mount_point, "dcim", TRUE))
01135 return FALSE;
01136
01137 dbg ("Photos detected: %s\n", mount_point);
01138
01139
01140 dbus_error_init (&error);
01141 if (!libhal_device_add_capability (hal_ctx, udi, "content.photos", &error)) {
01142 warn ("failed to set content.photos on %s: %s", device, error.message);
01143 dbus_error_free (&error);
01144 }
01145
01146 return TRUE;
01147 }
01148
01149
01150
01151
01152 static void
01153 gvm_run_portable_media_player (const char *udi, const char *device, const char *mount_point)
01154 {
01155 if (config.autoipod_command != NULL)
01156 gvm_run_command (config.autoipod_command, udi, device, mount_point);
01157 }
01158
01159
01160
01161
01162 static void
01163 gvm_run_pilot (const char *udi)
01164 {
01165 DBusError error;
01166 char *device;
01167
01168 if (config.autopilot_command == NULL)
01169 return;
01170
01171 dbus_error_init (&error);
01172
01173 if (!(device = libhal_device_get_property_string (hal_ctx, udi, "pda.palm.hotsync_interface", &error))) {
01174 warn ("cannot get pda.palm.hotsync_interface property: %s", error.message);
01175 if (dbus_error_is_set (&error))
01176 dbus_error_free (&error);
01177 return;
01178 }
01179
01180 gvm_run_command (config.autopilot_command, udi, device, NULL);
01181 libhal_free_string (device);
01182 }
01183
01184
01185
01186
01187 static void
01188 gvm_run_pocketpc (const char *udi)
01189 {
01190 DBusError error;
01191 char *device;
01192
01193 if (config.autopocketpc_command == NULL)
01194 return;
01195
01196 dbus_error_init (&error);
01197
01198 if (!(device = libhal_device_get_property_string (hal_ctx, udi, "pda.pocketpc.hotsync_interface", &error))) {
01199 warn ("cannot get pda.pocketpc.hotsync_interface property: %s", error.message);
01200 if (dbus_error_is_set (&error))
01201 dbus_error_free (&error);
01202 return;
01203 }
01204
01205 gvm_run_command (config.autopocketpc_command, udi, device, NULL);
01206 libhal_free_string (device);
01207 }
01208
01209
01210
01211
01212 static void
01213 gvm_run_printer (const char *udi)
01214 {
01215 DBusError error;
01216 char *device;
01217
01218 if (config.autoprinter_command == NULL)
01219 return;
01220
01221 dbus_error_init (&error);
01222 if (!(device = libhal_device_get_property_string (hal_ctx, udi, "printer.device", &error))) {
01223 warn ("cannot get printer.device property: %s", error.message);
01224 if (dbus_error_is_set (&error))
01225 dbus_error_free (&error);
01226 return;
01227 }
01228
01229 gvm_run_command (config.autoprinter_command, udi, device, NULL);
01230 libhal_free_string (device);
01231 }
01232
01233
01234
01235
01236 static void
01237 gvm_run_scanner (const char *udi)
01238 {
01239 char *device, *parent;
01240 DBusError error;
01241
01242 if (config.autoscanner_command == NULL)
01243 return;
01244
01245 dbus_error_init (&error);
01246 if (!(device = libhal_device_get_property_string (hal_ctx, udi, "scanner.device", &error))) {
01247
01248 if ((parent = libhal_device_get_property_string (hal_ctx, udi, "info.parent", NULL))) {
01249 if (dbus_error_is_set (&error))
01250 dbus_error_free (&error);
01251 dbus_error_init (&error);
01252 device = libhal_device_get_property_string (hal_ctx, parent, "linux.device_file", &error);
01253 libhal_free_string (parent);
01254 }
01255
01256 if (!device) {
01257 warn ("cannot get scanner.device property: %s", error.message);
01258 if (dbus_error_is_set (&error))
01259 dbus_error_free (&error);
01260 return;
01261 }
01262 }
01263
01264 gvm_run_command (config.autoscanner_command, udi, device, NULL);
01265 libhal_free_string (device);
01266 }
01267
01268
01269
01270
01271 static void
01272 gvm_run_webcam (const char *udi)
01273 {
01274 DBusError error;
01275 char *device;
01276
01277 if (config.autowebcam_command == NULL)
01278 return;
01279
01280 dbus_error_init (&error);
01281 if (!(device = libhal_device_get_property_string (hal_ctx, udi, "video4linux.device", &error))) {
01282 warn ("cannot get video4linux.device property: %s", error.message);
01283 if (dbus_error_is_set (&error))
01284 dbus_error_free (&error);
01285 return;
01286 }
01287
01288 gvm_run_command (config.autowebcam_command, udi, device, NULL);
01289 libhal_free_string (device);
01290 }
01291
01292 static void
01293 import_photos_cb (GvmPromptCtx *ctx, int action)
01294 {
01295 if (action == GVM_RESPONSE_IMPORT_PHOTOS)
01296 gvm_run_camera (ctx->udi, ctx->device, ctx->mount_point);
01297 }
01298
01299 static void
01300 gvm_run_filemanager (const char *udi, const char *device, const char *mount_point)
01301 {
01302 const char *command = NAUTILUS_COMMAND;
01303
01304 if (config.filemanager && *config.filemanager)
01305 command = config.filemanager;
01306
01307 gvm_run_command (command, udi, device, mount_point);
01308 }
01309
01310 #ifdef ENABLE_AUTOMOUNT
01311 static gboolean
01312 is_exe (const char *path)
01313 {
01314 size_t len;
01315
01316 return (len = strlen (path)) > 4 && !g_ascii_strcasecmp (path + len - 4, ".exe");
01317 }
01318
01319 static void
01320 autorun_cb (GvmPromptCtx *ctx, int action)
01321 {
01322 gboolean autobrowse = TRUE;
01323 GError *error = NULL;
01324 const char *prog;
01325 GPtrArray *args;
01326 struct stat st;
01327 char **argv;
01328 int argc, i;
01329
01330 if (action == GVM_RESPONSE_RUN || action == GVM_RESPONSE_OPEN) {
01331 if (!g_shell_parse_argv (ctx->path, &argc, &argv, NULL)) {
01332 argv = g_malloc (sizeof (char *) * 2);
01333 argv[0] = g_strdup (ctx->path);
01334 argv[1] = NULL;
01335 argc = 1;
01336 }
01337
01338 if (stat (argv[0], &st) == -1) {
01339 g_strfreev (argv);
01340 goto autobrowse;
01341 }
01342
01343 if (S_ISREG (st.st_mode) &&
01344 (access (argv[0], R_OK | X_OK) == 0 || is_exe (argv[0]))) {
01345
01346 args = g_ptr_array_new ();
01347
01348
01349
01350
01351 if (is_exe (argv[0]) && (prog = g_find_program_in_path ("wine")))
01352 g_ptr_array_add (args, (char *) prog);
01353
01354 for (i = 0; i < argc; i++)
01355 g_ptr_array_add (args, argv[i]);
01356 g_ptr_array_add (args, NULL);
01357
01358 g_spawn_async (ctx->mount_point, (char **) args->pdata, NULL,
01359 0, NULL, NULL, NULL, &error);
01360
01361 g_ptr_array_free (args, TRUE);
01362
01363 if (error)
01364 warn ("failed to exec %s: %s", ctx->path, error->message);
01365 else
01366 autobrowse = FALSE;
01367 } else if (argc > 1) {
01368
01369 warn ("failed to exec %s: %s", ctx->path, g_strerror (EACCES));
01370 } else if ((prog = g_find_program_in_path ("gnome-open"))) {
01371
01372 args = g_ptr_array_new ();
01373 g_ptr_array_add (args, (char *) prog);
01374 g_ptr_array_add (args, argv[0]);
01375 g_ptr_array_add (args, NULL);
01376
01377 g_spawn_async (ctx->mount_point, (char **) args->pdata, NULL,
01378 0, NULL, NULL, NULL, &error);
01379
01380 g_ptr_array_free (args, TRUE);
01381
01382 if (error)
01383 warn ("failed to open %s: %s", ctx->path, error->message);
01384 else
01385 autobrowse = FALSE;
01386 }
01387
01388 g_strfreev (argv);
01389 }
01390
01391 autobrowse:
01392
01393 if (config.autobrowse && autobrowse)
01394 gvm_run_filemanager (ctx->udi, ctx->device, ctx->mount_point);
01395 }
01396
01397 static char *
01398 canon_path (char *path)
01399 {
01400 register char *inptr, *outptr;
01401
01402 inptr = outptr = path;
01403
01404 while (*inptr != '\0') {
01405 if (inptr[0] == '.' && (inptr[1] == '/' || (inptr[1] == '.' && inptr[2] == '/'))) {
01406 if (inptr[1] == '.') {
01407
01408 inptr += 3;
01409
01410 if (outptr > path) {
01411 outptr--;
01412 while (outptr > path && outptr[-1] != '/')
01413 outptr--;
01414 if (outptr == path && *outptr == '/')
01415 outptr++;
01416 }
01417 } else {
01418
01419 inptr += 2;
01420 }
01421
01422 while (*inptr == '/')
01423 inptr++;
01424 }
01425
01426 while (*inptr && *inptr != '/')
01427 *outptr++ = *inptr++;
01428
01429 if (*inptr == '/')
01430 *outptr++ = *inptr++;
01431
01432 while (*inptr == '/')
01433 inptr++;
01434 }
01435
01436 *outptr = '\0';
01437
01438 return path;
01439 }
01440
01441 static char *
01442 unix_path (const char *mount_point, const char *rel_path)
01443 {
01444 const char *start, *inptr;
01445 gboolean checkstat = TRUE;
01446 struct dirent *dent;
01447 struct stat st;
01448 GString *path;
01449 size_t len;
01450 char *str;
01451 DIR *dir;
01452
01453 path = g_string_new (mount_point);
01454
01455 inptr = rel_path;
01456 while (*inptr) {
01457 start = inptr;
01458
01459 while (*inptr && *inptr != '\\')
01460 inptr++;
01461
01462 if (checkstat) {
01463 len = path->len;
01464
01465 g_string_append_c (path, G_DIR_SEPARATOR);
01466 g_string_append_len (path, start, inptr - start);
01467
01468 if (stat (path->str, &st) == -1) {
01469
01470 g_string_truncate (path, len);
01471
01472 len = inptr - start;
01473
01474 if ((dir = opendir (path->str))) {
01475 while ((dent = readdir (dir))) {
01476 if (!g_ascii_strncasecmp (dent->d_name, start, len))
01477 break;
01478 }
01479
01480 g_string_append_c (path, G_DIR_SEPARATOR);
01481
01482 if (dent == NULL) {
01483
01484 g_string_append_len (path, start, len);
01485 checkstat = FALSE;
01486 } else
01487 g_string_append (path, dent->d_name);
01488
01489 closedir (dir);
01490 } else {
01491 g_string_append_c (path, G_DIR_SEPARATOR);
01492 g_string_append_len (path, start, len);
01493 checkstat = FALSE;
01494 }
01495 }
01496 } else {
01497
01498 g_string_append_c (path, G_DIR_SEPARATOR);
01499 g_string_append_len (path, start, inptr - start);
01500 }
01501
01502 if (*inptr == '\0')
01503 break;
01504
01505 inptr++;
01506 }
01507
01508 str = path->str;
01509 g_string_free (path, FALSE);
01510
01511 return canon_path (str);
01512 }
01513
01514 static gboolean
01515 readline (FILE *fp, GString *linebuf)
01516 {
01517 gboolean eoln = FALSE;
01518 gboolean rv = FALSE;
01519 char buf[256];
01520 size_t n;
01521
01522 g_string_truncate (linebuf, 0);
01523
01524 while (!eoln && fgets (buf, sizeof (buf), fp)) {
01525 n = strlen (buf);
01526 rv = TRUE;
01527
01528 if (buf[n - 1] == '\n') {
01529 eoln = TRUE;
01530 buf[--n] = '\0';
01531 if (n > 0 && buf[n - 1] == '\r')
01532 buf[--n] = '\0';
01533 }
01534
01535 g_string_append_len (linebuf, buf, n);
01536 }
01537
01538 return rv;
01539 }
01540
01541 static char *
01542 autorun_inf_get (const char *path, const char *section, const char *key)
01543 {
01544 register char *inptr;
01545 char *value = NULL;
01546 GString *linebuf;
01547 gboolean rv;
01548 size_t len;
01549 FILE *fp;
01550
01551 if (!(fp = fopen (path, "rt")))
01552 return NULL;
01553
01554 len = strlen (key);
01555 linebuf = g_string_new ("");
01556
01557
01558 while ((rv = readline (fp, linebuf))) {
01559 g_strchomp (linebuf->str);
01560 if (!g_ascii_strcasecmp (linebuf->str, section))
01561 break;
01562 }
01563
01564 if (rv) {
01565
01566 while ((rv = readline (fp, linebuf))) {
01567 if (linebuf->str[0] == '[') {
01568
01569 break;
01570 }
01571
01572 if (g_ascii_strncasecmp (linebuf->str, key, len) != 0) {
01573
01574 continue;
01575 }
01576
01577
01578 inptr = linebuf->str + len;
01579 while (*inptr == ' ' || *inptr == '\t')
01580 inptr++;
01581
01582 if (*inptr == '\0') {
01583
01584 break;
01585 }
01586
01587 if (*inptr == '=') {
01588
01589 inptr++;
01590
01591 while (*inptr == ' ' || *inptr == '\t')
01592 inptr++;
01593
01594 if (*inptr) {
01595 value = g_strdup (inptr);
01596 g_strchug (value);
01597 }
01598
01599 break;
01600 }
01601 }
01602 }
01603
01604 g_string_free (linebuf, TRUE);
01605 fclose (fp);
01606
01607 return value;
01608 }
01609
01610 static gboolean
01611 gvm_autorun_prompt (GvmPrompt prompt, const char *udi, const char *device,
01612 const char *mount_point, char *value)
01613 {
01614 register char *inptr;
01615 char *argv[1], *path;
01616 GvmPromptCtx *ctx;
01617 GString *cmd;
01618 char c;
01619
01620 if (((value[0] >= 'A' && value[0] <= 'Z')
01621 || (value[0] >= 'a' && value[0] <= 'z'))
01622 && value[1] == ':' && value[2] == '\\') {
01623
01624
01625
01626 path = value + 3;
01627 } else {
01628 path = value;
01629 }
01630
01631
01632 inptr = path;
01633 while (*inptr && *inptr != ' ' && *inptr != '\t')
01634 inptr++;
01635
01636 c = *inptr;
01637 *inptr++ = '\0';
01638
01639 path = unix_path (mount_point, path);
01640 if (strncmp (path, mount_point, strlen (mount_point)) != 0) {
01641
01642 g_free (value);
01643 g_free (path);
01644 return FALSE;
01645 }
01646
01647 cmd = g_string_new (path);
01648
01649 if (c != '\0') {
01650 g_string_append_c (cmd, ' ');
01651 g_string_append (cmd, inptr);
01652 }
01653
01654 g_free (value);
01655
01656 argv[0] = path;
01657 ctx = gvm_prompt_ctx_new (prompt, autorun_cb, udi, device, mount_point, cmd->str);
01658 gvm_prompt (ctx, 1, argv);
01659 g_string_free (cmd, TRUE);
01660 g_free (path);
01661
01662 return TRUE;
01663 }
01664
01665 static gboolean
01666 gvm_autorun_inf (const char *udi, const char *device, const char *mount_point)
01667 {
01668 char *value, *path = NULL;
01669 struct dirent *dent;
01670 DIR *dir;
01671
01672 if ((dir = opendir (mount_point))) {
01673 while ((dent = readdir (dir))) {
01674 if (!g_ascii_strcasecmp (dent->d_name, "autorun.inf")) {
01675 path = g_build_filename (mount_point, dent->d_name, NULL);
01676 break;
01677 }
01678 }
01679
01680 closedir (dir);
01681 }
01682
01683 if (!path)
01684 return FALSE;
01685
01686 value = autorun_inf_get (path, "[autorun]", "open");
01687 g_free (path);
01688
01689 if (!value)
01690 return FALSE;
01691
01692 return gvm_autorun_prompt (GVM_PROMPT_AUTORUN, udi, device, mount_point, value);
01693 }
01694
01695 static gboolean
01696 gvm_autoopen (FILE *fp, const char *udi, const char *device, const char *mount_point)
01697 {
01698 GString *str;
01699 char *value;
01700
01701 str = g_string_new ("");
01702 if (!readline (fp, str)) {
01703 g_string_free (str, TRUE);
01704 return FALSE;
01705 }
01706
01707 value = str->str;
01708 g_strstrip (value);
01709 g_string_free (str, FALSE);
01710
01711 if (value[0] == '\0') {
01712
01713 g_free (value);
01714 return FALSE;
01715 }
01716
01717 return gvm_autorun_prompt (GVM_PROMPT_AUTOOPEN, udi, device, mount_point, value);
01718 }
01719 #endif
01720
01721
01722
01723
01724
01725
01726 static void
01727 gvm_autorun (const char *udi, const char *device, const char *mount_point)
01728 {
01729 #ifdef ENABLE_AUTOMOUNT
01730 char **autopath, *argv[1], *path;
01731 gboolean handled = FALSE;
01732 #endif
01733 GvmPromptCtx *ctx;
01734
01735 #ifdef ENABLE_AUTOMOUNT
01736 if (gvm_check_dvd (udi, device, mount_point))
01737 return;
01738
01739 if (gvm_check_vcd (udi, device, mount_point))
01740 return;
01741 #endif
01742
01743 if (config.autophoto && gvm_check_photos (udi, device, mount_point)) {
01744 ctx = gvm_prompt_ctx_new (GVM_PROMPT_IMPORT_PHOTOS, import_photos_cb, udi, device, mount_point, NULL);
01745 gvm_prompt (ctx, 0, NULL);
01746 return;
01747 }
01748
01749 #ifdef ENABLE_AUTOMOUNT
01750 if (config.autorun && config.autorun_path) {
01751 struct stat st;
01752 int i;
01753
01754 autopath = g_strsplit (config.autorun_path, ":", -1);
01755
01756 for (i = 0; autopath[i]; i++) {
01757 path = g_strdup_printf ("%s/%s", mount_point, autopath[i]);
01758 if (access (path, F_OK | R_OK | X_OK) != 0 || stat (path, &st) == -1
01759 || !S_ISREG (st.st_mode)) {
01760 g_free (path);
01761 continue;
01762 }
01763
01764 argv[0] = path;
01765 ctx = gvm_prompt_ctx_new (GVM_PROMPT_AUTORUN, autorun_cb, udi, device, mount_point, path);
01766 gvm_prompt (ctx, 1, argv);
01767 handled = TRUE;
01768 g_free (path);
01769 break;
01770 }
01771
01772 g_strfreev (autopath);
01773
01774 if (!handled)
01775 handled = gvm_autorun_inf (udi, device, mount_point);
01776
01777 if (handled)
01778 return;
01779 }
01780
01781 if (config.autoopen && config.autoopen_path) {
01782 FILE *fp;
01783 int i;
01784
01785 autopath = g_strsplit (config.autoopen_path, ":", -1);
01786
01787 for (i = 0; autopath[i]; i++) {
01788 path = g_strdup_printf ("%s/%s", mount_point, autopath[i]);
01789 if (!(fp = fopen (path, "rt"))) {
01790 g_free (path);
01791 continue;
01792 }
01793
01794 g_free (path);
01795
01796 handled = gvm_autoopen (fp, udi, device, mount_point);
01797 fclose (fp);
01798 break;
01799 }
01800
01801 g_strfreev (autopath);
01802
01803 if (handled)
01804 return;
01805 }
01806
01807 if (config.autobrowse)
01808 gvm_run_filemanager (udi, device, mount_point);
01809 #endif
01810 }
01811
01812 #ifdef ENABLE_AUTOMOUNT
01813 static gboolean
01814 gvm_udi_is_subfs_mount (const char *udi)
01815 {
01816 int subfs = FALSE;
01817 char **callouts;
01818 int i;
01819
01820 if ((callouts = libhal_device_get_property_strlist (hal_ctx, udi, "info.callouts.add", NULL))) {
01821 for (i = 0; callouts[i] != NULL; i++) {
01822 if (!strcmp (callouts[i], "hald-block-subfs")) {
01823 dbg ("subfs to handle mounting of %s; skipping\n", udi);
01824 subfs = TRUE;
01825 break;
01826 }
01827 }
01828
01829 libhal_free_string_array (callouts);
01830 }
01831
01832 return subfs;
01833 }
01834 #endif
01835
01836 static gboolean
01837 gvm_storage_device_is_cdrom (const char *storage)
01838 {
01839 gboolean is_cdrom = FALSE;
01840 char *media_type;
01841
01842 if ((media_type = libhal_device_get_property_string (hal_ctx, storage, "storage.drive_type", NULL))) {
01843 is_cdrom = !strcmp (media_type, "cdrom");
01844 libhal_free_string (media_type);
01845 }
01846
01847 return is_cdrom;
01848 }
01849
01850 static gboolean
01851 gvm_udi_is_cdrom (const char *udi)
01852 {
01853 gboolean is_cdrom;
01854 char *storage;
01855
01856 if (!(storage = libhal_device_get_property_string (hal_ctx, udi, "block.storage_device", NULL)))
01857 return FALSE;
01858
01859 is_cdrom = gvm_storage_device_is_cdrom (storage);
01860 libhal_free_string (storage);
01861
01862 return is_cdrom;
01863 }
01864
01865 static void
01866 import_storage_camera_cb (GvmPromptCtx *ctx, int action)
01867 {
01868 switch (action) {
01869 case GVM_RESPONSE_IMPORT_PHOTOS:
01870 gvm_run_camera (ctx->udi, ctx->device, ctx->mount_point);
01871 break;
01872 case GVM_RESPONSE_BROWSE:
01873 gvm_run_filemanager (ctx->udi, ctx->device, ctx->mount_point);
01874 break;
01875 default:
01876 break;
01877 }
01878 }
01879
01880 #ifdef ENABLE_AUTOMOUNT
01881 static void
01882 ipod_photo_cb (GvmPromptCtx *ctx, int action)
01883 {
01884 switch (action) {
01885 case GVM_RESPONSE_IMPORT_PHOTOS:
01886 gvm_run_camera (ctx->udi, ctx->device, ctx->path);
01887 break;
01888 case GVM_RESPONSE_SYNC_MUSIC:
01889 gvm_run_portable_media_player (ctx->udi, ctx->device, ctx->mount_point);
01890 break;
01891 default:
01892 break;
01893 }
01894 }
01895 #endif
01896
01897
01898
01899
01900
01901
01902
01903
01904 static void
01905 gvm_device_mounted (const char *udi)
01906 {
01907 char *mount_point = NULL;
01908 #ifdef ENABLE_AUTOMOUNT
01909 gboolean is_ipod = FALSE;
01910 #endif
01911 char *device = NULL;
01912 GvmPromptCtx *ctx;
01913 DBusError error;
01914
01915 dbus_error_init (&error);
01916 if (!(device = libhal_device_get_property_string (hal_ctx, udi, "block.device", &error))) {
01917 warn ("cannot get block.device: %s", error.message);
01918 if (dbus_error_is_set (&error))
01919 dbus_error_free (&error);
01920 goto out;
01921 }
01922
01923 if (!(mount_point = libhal_device_get_property_string (hal_ctx, udi, "volume.mount_point", &error))) {
01924 warn ("cannot get volume.mount_point: %s", error.message);
01925 if (dbus_error_is_set (&error))
01926 dbus_error_free (&error);
01927 goto out;
01928 }
01929
01930 #ifdef ENABLE_AUTOMOUNT
01931
01932 if (config.autophoto && gvm_udi_is_storage_camera (udi)) {
01933 ctx = gvm_prompt_ctx_new (GVM_PROMPT_IMPORT_STORAGE_CAMERA, import_storage_camera_cb,
01934 udi, device, mount_point, NULL);
01935 gvm_prompt (ctx, 0, NULL);
01936 } else if (config.autoipod && gvm_udi_is_portable_media_player (udi, &is_ipod)) {
01937 char *ipod_control = NULL;
01938 const char *photo_dir;
01939
01940 if (is_ipod) {
01941 ipod_control = g_build_filename (mount_point, "iPod_Control", NULL);
01942 photo_dir = ipod_control;
01943 } else {
01944 photo_dir = mount_point;
01945 }
01946
01947 if (gvm_check_photos (udi, device, photo_dir)) {
01948
01949 ctx = gvm_prompt_ctx_new (GVM_PROMPT_IPOD_PHOTO, ipod_photo_cb,
01950 udi, device, mount_point, photo_dir);
01951 gvm_prompt (ctx, 0, NULL);
01952 } else {
01953 gvm_run_portable_media_player (udi, device, mount_point);
01954 }
01955
01956 g_free (ipod_control);
01957 } else {
01958 gvm_autorun (udi, device, mount_point);
01959 }
01960 #else
01961
01962 if (config.autophoto && gvm_udi_is_storage_camera (udi)) {
01963 ctx = gvm_prompt_ctx_new (GVM_PROMPT_IMPORT_STORAGE_CAMERA, import_storage_camera_cb,
01964 udi, device, mount_point, NULL);
01965 gvm_prompt (ctx, 0, NULL);
01966 } else {
01967 gvm_autorun (udi, device, mount_point);
01968 }
01969 #endif
01970
01971 out:
01972
01973 libhal_free_string (mount_point);
01974 libhal_free_string (device);
01975 }
01976
01977
01978 #ifdef ENABLE_AUTOMOUNT
01979 enum {
01980 MOUNT_CODEPAGE = (1 << 0),
01981 MOUNT_DATA = (1 << 1),
01982 MOUNT_DIRSYNC = (1 << 2),
01983 MOUNT_DMASK = (1 << 3),
01984 MOUNT_FMASK = (1 << 4),
01985 MOUNT_FLUSH = (1 << 5),
01986 MOUNT_IOCHARSET = (1 << 6),
01987 MOUNT_MODE = (1 << 7),
01988 MOUNT_NOATIME = (1 << 8),
01989 MOUNT_NODIRATIME = (1 << 9),
01990 MOUNT_NOEXEC = (1 << 10),
01991 MOUNT_QUIET = (1 << 11),
01992 MOUNT_READ_ONLY = (1 << 12),
01993 MOUNT_SHORTNAME = (1 << 13),
01994 MOUNT_SYNC = (1 << 14),
01995 MOUNT_UID = (1 << 15),
01996 MOUNT_UMASK = (1 << 16),
01997 MOUNT_UTF8 = (1 << 17),
01998 };
01999
02000 static struct {
02001 const char *name;
02002 guint32 flag;
02003 } mount_options[] = {
02004 { "codepage=", MOUNT_CODEPAGE },
02005 { "data=", MOUNT_DATA },
02006 { "dirsync", MOUNT_DIRSYNC },
02007 { "dmask=", MOUNT_DMASK },
02008 { "fmask=", MOUNT_FMASK },
02009 { "flush", MOUNT_FLUSH },
02010 { "iocharset=", MOUNT_IOCHARSET },
02011 { "mode=", MOUNT_MODE },
02012 { "noatime", MOUNT_NOATIME },
02013 { "nodiratime", MOUNT_NODIRATIME },
02014 { "noexec", MOUNT_NOEXEC },
02015 { "quiet", MOUNT_QUIET },
02016 { "ro", MOUNT_READ_ONLY },
02017 { "shortname=", MOUNT_SHORTNAME },
02018 { "sync", MOUNT_SYNC },
02019 { "uid=", MOUNT_UID },
02020 { "umask=", MOUNT_UMASK },
02021 { "utf8", MOUNT_UTF8 },
02022 };
02023
02024
02025 static const char *
02026 canonicalize_codeset (char *str)
02027 {
02028 register char *s = str;
02029 register char *d = str;
02030
02031 while (*s) {
02032 if (*s >= 'A' && *s <= 'Z')
02033 *d++ = *s++ + 0x20;
02034 else if (*s != '-' && *s != '_')
02035 *d++ = *s++;
02036 else
02037 s++;
02038 }
02039
02040 *d = '\0';
02041
02042 return str;
02043 }
02044
02045 static struct {
02046 const char *codeset;
02047 const char *iocharset;
02048 } iocharset_mapping[] = {
02049 { "tis620", "cp874" },
02050
02051 { "shiftjis*", "cp932" },
02052 { "sjis", "cp932" },
02053
02054 { "gb18030", "cp936" },
02055 { "gbk", "cp936" },
02056 { "gb2312", "cp936" },
02057
02058 { "euckr", "cp949" },
02059
02060 { "big5*", "cp950" },
02061 { "euctw", "cp950" },
02062
02063
02064
02065 { "eucjp", "euc-jp" },
02066
02067 { "iso88591", "iso8859-1" },
02068 { "iso88592", "iso8859-2" },
02069 { "iso88593", "iso8859-3" },
02070 { "iso88594", "iso8859-4" },
02071 { "iso88595", "iso8859-5" },
02072 { "iso88596", "iso8859-6" },
02073 { "iso88597", "iso8859-7" },
02074 { "iso88599", "iso8859-9" },
02075 { "iso885913", "iso8859-13" },
02076 { "iso885914", "iso8859-14" },
02077 { "iso885915", "iso8859-15" },
02078
02079 { "koi8r", "koi8-r" },
02080 { "koi8u", "koi8-u" },
02081
02082
02083 };
02084
02085 static const char *
02086 gvm_iocharset (void)
02087 {
02088 static const char *iocharset = NULL;
02089 char *locale, *codeset, *inptr;
02090 static int initialized = FALSE;
02091 const char *wildcard;
02092 size_t i, n;
02093
02094 if (initialized)
02095 return iocharset;
02096
02097 initialized = TRUE;
02098
02099 locale = setlocale (LC_ALL, NULL);
02100 if (!locale || !strcmp (locale, "C") || !strcmp (locale, "POSIX")) {
02101
02102
02103
02104
02105
02106 iocharset = NULL;
02107 } else {
02108 #ifdef HAVE_CODESET
02109 codeset = g_strdup (nl_langinfo (CODESET));
02110 canonicalize_codeset (codeset);
02111 #else
02112
02113
02114
02115
02116
02117
02118 if (!(codeset = strchr (locale, '.'))) {
02119
02120 return NULL;
02121 }
02122
02123 codeset++;
02124
02125
02126 inptr = codeset;
02127 while (*inptr && !strchr ("@;/", *inptr))
02128 inptr++;
02129
02130 codeset = g_strndup (codeset, inptr - codeset);
02131 canonicalize_codeset (codeset);
02132 #endif
02133
02134 for (i = 0; i < G_N_ELEMENTS (iocharset_mapping); i++) {
02135 if ((wildcard = strchr (iocharset_mapping[i].codeset, '*'))) {
02136 n = wildcard - iocharset_mapping[i].codeset;
02137 if (!strncmp (codeset, iocharset_mapping[i].codeset, n)) {
02138 iocharset = iocharset_mapping[i].iocharset;
02139 break;
02140 }
02141 } else if (!strcmp (codeset, iocharset_mapping[i].codeset)) {
02142 iocharset = iocharset_mapping[i].iocharset;
02143 break;
02144 }
02145 }
02146
02147 if (!iocharset) {
02148 iocharset = codeset;
02149 codeset = NULL;
02150 }
02151
02152 g_free (codeset);
02153 }
02154
02155 return iocharset;
02156 }
02157
02158
02159 static gboolean
02160 gvm_mount_options (GPtrArray *options, guint32 opts, const char *type, const char *where)
02161 {
02162 char *option, *key, *tmp, *p;
02163 GSList *list, *l, *n;
02164 GConfClient *gconf;
02165 const char *dir;
02166
02167 if (!strncmp (where, "/org/freedesktop/Hal/", 21)) {
02168
02169 dir = p = tmp = g_strdup (where);
02170 while (*p != '\0') {
02171 if (*p == '/')
02172 *p = '_';
02173 p++;
02174 }
02175 } else {
02176 dir = where;
02177 tmp = NULL;
02178 }
02179
02180 key = g_strdup_printf ("/system/storage/%s/%s/mount_options", type, dir);
02181 g_free (tmp);
02182
02183 gconf = gconf_client_get_default ();
02184 list = gconf_client_get_list (gconf, key, GCONF_VALUE_STRING, NULL);
02185 g_object_unref (gconf);
02186 g_free (key);
02187
02188 if (list == NULL) {
02189 fprintf (stderr, "no mount options found for %s::%s\n", type, where);
02190 return FALSE;
02191 }
02192
02193 for (l = list; l != NULL; l = n) {
02194 option = l->data;
02195 n = l->next;
02196
02197 g_ptr_array_add (options, option);
02198
02199 g_slist_free_1 (l);
02200 }
02201
02202 if (opts & MOUNT_UID) {
02203 option = g_strdup_printf ("uid=%u", getuid ());
02204 g_ptr_array_add (options, option);
02205 }
02206
02207 return TRUE;
02208 }
02209
02210
02211
02212
02213
02214
02215
02216 static gboolean
02217 gvm_device_mount (const char *udi, gboolean interactive)
02218 {
02219 struct _MountPolicy *policy;
02220
02221 dbg ("mounting %s...\n", udi);
02222
02223 if (!gnome_mount || access (gnome_mount, F_OK | R_OK | X_OK) != 0) {
02224 g_free (gnome_mount);
02225 gnome_mount = g_find_program_in_path ("gnome-mount");
02226 }
02227
02228 if (gnome_mount != NULL) {
02229 gboolean retval;
02230 char *command;
02231
02232 policy = g_new (struct _MountPolicy, 1);
02233 policy->udi = g_strdup (udi);
02234 policy->apply = interactive;
02235
02236 g_hash_table_insert (mount_table, policy->udi, policy);
02237
02238 if (!interactive) {
02239 command = g_strdup_printf ("%s --no-ui --hal-udi=%%h", gnome_mount);
02240 } else {
02241 command = g_strdup_printf ("%s --hal-udi=%%h", gnome_mount);
02242 }
02243
02244 retval = gvm_run_command (command, udi, NULL, NULL);
02245 g_free (command);
02246
02247 if (!retval) {
02248 g_hash_table_remove (mount_table, policy->udi);
02249 g_free (policy->udi);
02250 g_free (policy);
02251 }
02252
02253 return retval;
02254 } else {
02255 char *mount_point, *fstype, *drive, **moptions, fmask_opt[12], *charset_opt = NULL;
02256 DBusMessage *dmesg, *reply;
02257 gboolean freev = FALSE;
02258 GPtrArray *options;
02259 guint32 opts = 0;
02260 DBusError error;
02261 size_t i, j;
02262
02263 if (!(dmesg = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
02264 "org.freedesktop.Hal.Device.Volume",
02265 "Mount"))) {
02266 dbg ("mount failed for %s: could not create dbus message\n", udi);
02267 return FALSE;
02268 }
02269
02270 if ((moptions = libhal_device_get_property_strlist (hal_ctx, udi, "volume.mount.valid_options", NULL))) {
02271 for (i = 0; moptions[i]; i++) {
02272 for (j = 0; j < G_N_ELEMENTS (mount_options); j++) {
02273 if (!strcmp (moptions[i], mount_options[j].name))
02274 opts |= mount_options[j].flag;
02275 }
02276 }
02277
02278 libhal_free_string_array (moptions);
02279 }
02280
02281 options = g_ptr_array_new ();
02282
02283
02284 if (gvm_mount_options (options, opts, "volumes", udi)) {
02285 freev = TRUE;
02286 goto mount;
02287 }
02288
02289
02290 if ((drive = libhal_device_get_property_string (hal_ctx, udi, "block.storage_device", NULL))) {
02291 if (gvm_mount_options (options, opts, "drives", drive)) {
02292 libhal_free_string (drive);
02293 freev = TRUE;
02294 goto mount;
02295 }
02296 libhal_free_string (drive);
02297 }
02298
02299 if ((fstype = libhal_device_get_property_string (hal_ctx, udi, "volume.fstype", NULL))) {
02300 const char *iocharset;
02301 char uid[32];
02302 mode_t mask;
02303
02304
02305 if (gvm_mount_options (options, opts, "default_options", fstype)) {
02306 libhal_free_string (fstype);
02307 freev = TRUE;
02308 goto mount;
02309 } else if (gvm_mount_options (options, opts, "default_options", "*")) {
02310 libhal_free_string (fstype);
02311 freev = TRUE;
02312 goto mount;
02313 }
02314
02315
02316 if (!strcmp (fstype, "vfat")) {
02317 if (opts & MOUNT_NOEXEC)
02318 g_ptr_array_add (options, "noexec");
02319
02320
02321
02322
02323 if (opts & MOUNT_FLUSH) {
02324 g_ptr_array_add (options, "flush");
02325 } else if (opts & MOUNT_SYNC) {
02326 dbus_uint64_t size;
02327
02328 size = libhal_device_get_property_uint64 (hal_ctx, udi, "volume.size", NULL);
02329 if (size <= (512 * 1024 * 1024))
02330 g_ptr_array_add (options, "sync");
02331 }
02332
02333 if (opts & MOUNT_FMASK) {
02334 mask = umask (0);
02335 snprintf (fmask_opt, sizeof (fmask_opt), "fmask=%#o", mask | 0111);
02336 g_ptr_array_add (options, fmask_opt);
02337 umask (mask);
02338 }
02339
02340 if (opts & MOUNT_SHORTNAME)
02341 g_ptr_array_add (options, "shortname=lower");
02342 } else if (!strcmp (fstype, "iso9660")) {
02343
02344 } else if (!strcmp (fstype, "udf")) {
02345
02346 if (opts & MOUNT_NOATIME)
02347 g_ptr_array_add (options, "noatime");
02348 }
02349
02350 if (opts & (MOUNT_IOCHARSET|MOUNT_UTF8)) {
02351 if ((iocharset = gvm_iocharset ())) {
02352 if ((opts & MOUNT_UTF8) && !strcmp (iocharset, "utf8")) {
02353 g_ptr_array_add (options, "utf8");
02354 } else if (opts & MOUNT_IOCHARSET) {
02355 charset_opt = g_strdup_printf ("iocharset=%s", iocharset);
02356 g_ptr_array_add (options, charset_opt);
02357 }
02358 }
02359 }
02360
02361 if (opts & MOUNT_UID) {
02362 snprintf (uid, sizeof (uid) - 1, "uid=%u", getuid ());
02363 g_ptr_array_add (options, uid);
02364 }
02365
02366 libhal_free_string (fstype);
02367 }
02368
02369 mount:
02370
02371 mount_point = "";
02372 fstype = "";
02373
02374 if (!dbus_message_append_args (dmesg, DBUS_TYPE_STRING, &mount_point, DBUS_TYPE_STRING, &fstype,
02375 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &options->pdata, options->len,
02376 DBUS_TYPE_INVALID)) {
02377 dbg ("mount failed for %s: could not append args to dbus message\n", udi);
02378 dbus_message_unref (dmesg);
02379 return FALSE;
02380 }
02381
02382 if (freev) {
02383 for (i = 0; i < options->len; i++)
02384 g_free (options->pdata[i]);
02385 }
02386
02387 g_ptr_array_free (options, TRUE);
02388 g_free (charset_opt);
02389
02390 policy = g_new (struct _MountPolicy, 1);
02391 policy->udi = g_strdup (udi);
02392 policy->apply = interactive;
02393
02394 g_hash_table_insert (mount_table, policy->udi, policy);
02395
02396 dbus_error_init (&error);
02397 if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, dmesg, -1, &error))) {
02398 dbg ("mount failed for %s: %s\n", udi, error.message);
02399 g_hash_table_remove (mount_table, policy->udi);
02400 dbus_message_unref (dmesg);
02401 dbus_error_free (&error);
02402 g_free (policy->udi);
02403 g_free (policy);
02404 return FALSE;
02405 }
02406
02407 dbg ("mount queued for %s\n", udi);
02408
02409 dbus_message_unref (dmesg);
02410 dbus_message_unref (reply);
02411
02412 return TRUE;
02413 }
02414 }
02415
02416
02417
02418
02419
02420
02421
02422 static gboolean
02423 gvm_device_unmount (const char *udi)
02424 {
02425 DBusMessage *dmesg, *reply;
02426 char **options = NULL;
02427 DBusError error;
02428 gboolean retval;
02429 char *command;
02430
02431 dbg ("unmounting %s...\n", udi);
02432
02433 if (!gnome_mount || access (gnome_mount, F_OK | R_OK | X_OK) != 0) {
02434 g_free (gnome_mount);
02435 gnome_mount = g_find_program_in_path ("gnome-mount");
02436 }
02437
02438 if (gnome_mount != NULL) {
02439 command = g_strdup_printf ("%s --unmount --hal-udi=%%h", gnome_mount);
02440 retval = gvm_run_command (command, udi, NULL, NULL);
02441 g_free (command);
02442
02443 return retval;
02444 } else {
02445 if (!(dmesg = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
02446 "org.freedesktop.Hal.Device.Volume",
02447 "Unmount"))) {
02448 dbg ("unmount failed for %s: could not create dbus message\n", udi);
02449 return FALSE;
02450 }
02451
02452 if (!dbus_message_append_args (dmesg, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &options, 0,
02453 DBUS_TYPE_INVALID)) {
02454 dbg ("unmount failed for %s: could not append args to dbus message\n", udi);
02455 dbus_message_unref (dmesg);
02456 return FALSE;
02457 }
02458
02459 dbus_error_init (&error);
02460 if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, dmesg, -1, &error))) {
02461 dbg ("unmount failed for %s: %s\n", udi, error.message);
02462 dbus_message_unref (dmesg);
02463 dbus_error_free (&error);
02464 return FALSE;
02465 }
02466
02467 dbg ("unmount queued for %s\n", udi);
02468
02469 dbus_message_unref (dmesg);
02470 dbus_message_unref (reply);
02471
02472 return TRUE;
02473 }
02474 }
02475
02476
02477
02478
02479
02480 static void
02481 gvm_run_cdplayer (const char *udi, const char *device, const char *mount_point)
02482 {
02483 if (config.autoplay_cda_command != NULL)
02484 gvm_run_command (config.autoplay_cda_command, udi, device, mount_point);
02485 }
02486
02487 static void
02488 cda_extra_cb (GvmPromptCtx *ctx, int action)
02489 {
02490 switch (action) {
02491 case GVM_RESPONSE_BROWSE:
02492 if (!gvm_udi_is_subfs_mount (ctx->udi))
02493 gvm_device_mount (ctx->udi, TRUE);
02494 break;
02495 case GVM_RESPONSE_PLAY:
02496 gvm_run_cdplayer (ctx->udi, ctx->device, NULL);
02497 break;
02498 default:
02499 break;
02500 }
02501 }
02502
02503
02504
02505
02506
02507
02508
02509 static void
02510 gvm_ask_mixed (const char *udi)
02511 {
02512 char *device = NULL;
02513 GvmPromptCtx *ctx;
02514 DBusError error;
02515
02516 dbus_error_init (&error);
02517 if (!(device = libhal_device_get_property_string (hal_ctx, udi, "block.device", &error))) {
02518 warn ("cannot get block.device: %s", error.message);
02519 dbus_error_free (&error);
02520 return;
02521 }
02522
02523 if (config.automount_media && config.autoplay_cda) {
02524 ctx = gvm_prompt_ctx_new (GVM_PROMPT_CDA_EXTRA, cda_extra_cb, udi, device, NULL, NULL);
02525 gvm_prompt (ctx, 0, NULL);
02526 } else if (config.automount_media) {
02527 if (!gvm_udi_is_subfs_mount (udi))
02528 gvm_device_mount (udi, TRUE);
02529 } else if (config.autoplay_cda) {
02530 gvm_run_cdplayer (udi, device, NULL);
02531 }
02532
02533 libhal_free_string (device);
02534 }
02535
02536
02537 typedef enum {
02538 WRITER_TYPE_NONE,
02539 WRITER_TYPE_CDR,
02540 WRITER_TYPE_DVD
02541 } writer_t;
02542
02543 static struct {
02544 const char *disc;
02545 const char *drive;
02546 writer_t type;
02547 } burners[] = {
02548 { "cd_r", "storage.cdrom.cdr", WRITER_TYPE_CDR },
02549 { "cd_rw", "storage.cdrom.cdrw", WRITER_TYPE_CDR },
02550 { "dvd_r", "storage.cdrom.dvdr", WRITER_TYPE_DVD },
02551 { "dvd_rw", "storage.cdrom.dvdrw", WRITER_TYPE_DVD },
02552 { "dvd_ram", "storage.cdrom.dvdram", WRITER_TYPE_DVD },
02553 { "dvd_plus_r", "storage.cdrom.dvdplusr", WRITER_TYPE_DVD },
02554 { "dvd_plus_rw", "storage.cdrom.dvdplusrw", WRITER_TYPE_DVD },
02555 };
02556
02557
02558
02559
02560 static writer_t
02561 gvm_cdrom_media_is_writable (const char *udi)
02562 {
02563 writer_t retval = WRITER_TYPE_NONE;
02564 char *drive = NULL;
02565 char *disc = NULL;
02566 size_t i;
02567
02568 if (!(disc = libhal_device_get_property_string (hal_ctx, udi, "volume.disc.type", NULL)))
02569 return FALSE;
02570
02571 for (i = 0; i < G_N_ELEMENTS (burners); i++) {
02572 if (!strcmp (burners[i].disc, disc)) {
02573 if (!(drive = libhal_device_get_property_string (hal_ctx, udi, "info.parent", NULL)))
02574 break;
02575
02576 if (libhal_device_get_property_bool (hal_ctx, drive, burners[i].drive, NULL))
02577 retval = burners[i].type;
02578
02579 break;
02580 }
02581 }
02582
02583 libhal_free_string (drive);
02584 libhal_free_string (disc);
02585
02586 return retval;
02587 }
02588
02589 static void
02590 burn_cdr_cb (GvmPromptCtx *ctx, int action)
02591 {
02592 const char *command;
02593
02594 switch (action) {
02595 case GVM_RESPONSE_WRITE_AUDIO_CD:
02596 command = config.autoburn_audio_cd_command;
02597 break;
02598 case GVM_RESPONSE_WRITE_DATA_CD:
02599 command = config.autoburn_data_cd_command;
02600 break;
02601 default:
02602 return;
02603 }
02604
02605 gvm_run_command (command, ctx->udi, ctx->device, ctx->mount_point);
02606 }
02607
02608
02609
02610
02611
02612 static void
02613 gvm_run_cdburner (const char *udi, int type, const char *device, const char *mount_point)
02614 {
02615 GvmPromptCtx *ctx;
02616 GvmPrompt prompt;
02617
02618 if (!config.autoburn)
02619 return;
02620
02621 if (type == WRITER_TYPE_DVD)
02622 prompt = GVM_PROMPT_WRITE_DVD;
02623 else
02624 prompt = GVM_PROMPT_WRITE_CDR;
02625
02626 ctx = gvm_prompt_ctx_new (prompt, burn_cdr_cb, udi, device, mount_point, NULL);
02627 gvm_prompt (ctx, 0, NULL);
02628 }
02629
02630
02631
02632
02633
02634
02635 static void
02636 gvm_cdrom_policy (const char *udi)
02637 {
02638 dbus_bool_t has_audio;
02639 dbus_bool_t has_data;
02640 char *device = NULL;
02641 DBusError error;
02642 writer_t type;
02643
02644 dbus_error_init (&error);
02645 if (!(device = libhal_device_get_property_string (hal_ctx, udi, "block.device", &error))) {
02646 warn ("cannot get block.device: %s", error.message);
02647 dbus_error_free (&error);
02648 return;
02649 }
02650
02651 if (libhal_device_get_property_bool (hal_ctx, udi, "volume.disc.is_blank", NULL)) {
02652 if ((type = gvm_cdrom_media_is_writable (udi)))
02653 gvm_run_cdburner (udi, type, device, NULL);
02654 } else {
02655 has_audio = libhal_device_get_property_bool (hal_ctx, udi, "volume.disc.has_audio", NULL);
02656 has_data = libhal_device_get_property_bool (hal_ctx, udi, "volume.disc.has_data", NULL);
02657
02658 if (has_audio && has_data) {
02659 gvm_ask_mixed (udi);
02660 } else if (has_audio) {
02661 if (config.autoplay_cda)
02662 gvm_run_cdplayer (udi, device, NULL);
02663 } else if (has_data) {
02664 if (config.automount_media && !gvm_udi_is_subfs_mount (udi))
02665 gvm_device_mount (udi, TRUE);
02666 }
02667 }
02668
02669
02670
02671 libhal_free_string (device);
02672 }
02673
02674
02675
02676
02677
02678
02679
02680
02681
02682
02683
02684
02685
02686 static gboolean
02687 gvm_media_changed (const char *udi, const char *storage_device)
02688 {
02689 gboolean handled = FALSE;
02690 DBusError error;
02691
02692
02693 dbus_error_init (&error);
02694 if (libhal_device_property_exists (hal_ctx, storage_device, "info.locked", NULL)
02695 && libhal_device_get_property_bool (hal_ctx, storage_device, "info.locked", NULL)) {
02696 dbg ("Drive with udi %s is locked through hal; skipping policy\n", storage_device);
02697
02698 return TRUE;
02699 }
02700
02701 if (gvm_storage_device_is_cdrom (storage_device)) {
02702 gvm_cdrom_policy (udi);
02703 handled = TRUE;
02704 }
02705
02706 return handled;
02707 }
02708 #endif
02709
02710
02711 static void
02712 import_camera_cb (GvmPromptCtx *ctx, int action)
02713 {
02714 if (action == GVM_RESPONSE_IMPORT_PHOTOS)
02715 gvm_run_camera (ctx->udi, NULL, NULL);
02716 }
02717
02718
02719 static int
02720 strptrcmp (const void *strptr0, const void *strptr1)
02721 {
02722 return strcmp (*((const char **) strptr0), *((const char **) strptr1));
02723 }
02724
02725
02726 typedef gboolean (* DeviceAddedHandler) (const char *udi, const char *capability);
02727
02728 #ifdef ENABLE_AUTOMOUNT
02729 static gboolean
02730 block_device_added (const char *udi, const char *capability GNUC_UNUSED)
02731 {
02732 char *fsusage = NULL, *device = NULL, *storage_device = NULL;
02733 DBusError error;
02734 int mountable;
02735 int crypto;
02736
02737 dbus_error_init (&error);
02738
02739 crypto = FALSE;
02740
02741
02742 if (!(mountable = libhal_device_get_property_bool (hal_ctx, udi, "block.is_volume", NULL))) {
02743 dbg ("not a mountable volume: %s\n", udi);
02744 goto out;
02745 }
02746
02747
02748 if (!(device = libhal_device_get_property_string (hal_ctx, udi, "block.device", &error))) {
02749 dbg ("cannot get block.device: %s\n", error.message);
02750 goto out;
02751 }
02752
02753 if (mountable) {
02754
02755 if (!(fsusage = libhal_device_get_property_string (hal_ctx, udi, "volume.fsusage", &error))) {
02756 dbg ("unable to get fsusage for %s: %s\n", udi, error.message);
02757 mountable = FALSE;
02758 } else if (!strcmp (fsusage, "crypto")) {
02759 dbg ("encrypted volume found: %s\n", udi);
02760
02761 mountable = FALSE;
02762 crypto = TRUE;
02763 } else if (strcmp (fsusage, "filesystem") != 0) {
02764 dbg ("no sensible filesystem for %s\n", udi);
02765 mountable = FALSE;
02766 }
02767 }
02768
02769
02770 if (!(storage_device = libhal_device_get_property_string (hal_ctx, udi, "block.storage_device", &error))) {
02771 dbg ("cannot get block.storage_device: %s\n", error.message);
02772 goto out;
02773 }
02774
02775
02776
02777
02778 if (libhal_device_get_property_bool (hal_ctx, storage_device, "storage.partition_table_changed", NULL)) {
02779 dbg ("partition table changed for %s\n", storage_device);
02780 goto out;
02781 }
02782
02783
02784
02785
02786
02787 if (libhal_device_get_property_bool (hal_ctx, storage_device, "storage.removable", NULL)) {
02788
02789 dbg ("Changed: %s\n", device);
02790 if (gvm_media_changed (udi, storage_device))
02791 goto out;
02792 }
02793
02794 if (config.automount_drives && (mountable || crypto)) {
02795 if (!gvm_udi_is_subfs_mount (udi)) {
02796 if (libhal_device_get_property_bool (hal_ctx, udi, "volume.ignore", NULL)) {
02797 dbg ("volume.ignore set to true on %s, not mounting\n", udi);
02798 } else if (!libhal_device_get_property_bool (hal_ctx, storage_device, "storage.automount_enabled_hint", NULL)) {
02799 dbg ("automounting disabled for %s, not mounting\n", storage_device);
02800 } else {
02801 gvm_device_mount (udi, TRUE);
02802 }
02803 }
02804 }
02805
02806 out:
02807
02808 if (dbus_error_is_set (&error))
02809 dbus_error_free (&error);
02810
02811 libhal_free_string (device);
02812 libhal_free_string (fsusage);
02813 libhal_free_string (storage_device);
02814
02815 return TRUE;
02816 }
02817 #endif
02818
02819 static gboolean
02820 camera_device_added (const char *udi, const char *capability GNUC_UNUSED)
02821 {
02822 GvmPromptCtx *ctx;
02823
02824
02825 if (!gvm_udi_is_camera (udi))
02826 return TRUE;
02827
02828 if (!(config.autophoto && config.autophoto_command))
02829 return FALSE;
02830
02831 ctx = gvm_prompt_ctx_new (GVM_PROMPT_IMPORT_CAMERA, import_camera_cb, udi, NULL, NULL, NULL);
02832 gvm_prompt (ctx, 0, NULL);
02833
02834 return TRUE;
02835 }
02836
02837 static struct {
02838 const char *capability;
02839 gboolean *autoexec;
02840 char **command;
02841 } inputs[] = {
02842 { "input.keyboard", &config.autokeyboard, &config.autokeyboard_command },
02843 { "input.mouse", &config.automouse, &config.automouse_command },
02844 { "input.tablet", &config.autotablet, &config.autotablet_command },
02845 };
02846
02847 static gboolean
02848 input_device_added (const char *udi, const char *capability)
02849 {
02850
02851 const char *command = NULL;
02852 int autoexec = FALSE;
02853 DBusError error;
02854 char *device;
02855 size_t i;
02856
02857 for (i = 0; i < G_N_ELEMENTS (inputs); i++) {
02858 if (!strcmp (inputs[i].capability, capability)) {
02859 autoexec = *inputs[i].autoexec;
02860 command = *inputs[i].command;
02861 break;
02862 }
02863 }
02864
02865 if (i == G_N_ELEMENTS (inputs)) {
02866
02867 return FALSE;
02868 }
02869
02870 if (autoexec && command) {
02871 dbus_error_init (&error);
02872 if ((device = libhal_device_get_property_string (hal_ctx, udi, "input.device", &error))) {
02873 gvm_run_command (command, udi, device, NULL);
02874 libhal_free_string (device);
02875 } else {
02876 warn ("cannot get input.device property: %s", error.message);
02877 dbus_error_free (&error);
02878 }
02879
02880 return TRUE;
02881 }
02882
02883 return FALSE;
02884 }
02885
02886 static gboolean
02887 pda_device_added (const char *udi, const char *capability GNUC_UNUSED)
02888 {
02889 DBusError error;
02890 char *platform;
02891
02892 dbus_error_init (&error);
02893
02894 if (!(platform = libhal_device_get_property_string (hal_ctx, udi, "pda.platform", &error))) {
02895 warn ("cannot get pda.platform property: %s", error.message);
02896 dbus_error_free (&error);
02897 return TRUE;
02898 }
02899
02900 if (!strcmp (platform, "palm")) {
02901 if (config.autopilot)
02902 gvm_run_pilot (udi);
02903 } else if (!strcmp (platform, "pocketpc")) {
02904 if (config.autopocketpc)
02905 gvm_run_pocketpc (udi);
02906 }
02907
02908 libhal_free_string (platform);
02909
02910 return TRUE;
02911 }
02912
02913 static gboolean
02914 media_player_device_added (const char *udi, const char *capability GNUC_UNUSED)
02915 {
02916 char *access_method;
02917 DBusError error;
02918
02919 dbus_error_init (&error);
02920
02921 if (!(access_method = libhal_device_get_property_string (hal_ctx, udi, "portable_audio_player.access_method", &error))) {
02922 warn ("cannot get portable_audio_player.access_method property: %s", error.message);
02923 dbus_error_free (&error);
02924 return TRUE;
02925 }
02926
02927 if (!strcmp (access_method, "storage")) {
02928
02929 g_free (access_method);
02930 return TRUE;
02931 }
02932
02933 g_free (access_method);
02934
02935 if (config.autoipod)
02936 gvm_run_portable_media_player (udi, NULL, NULL);
02937
02938 return TRUE;
02939 }
02940
02941 static gboolean
02942 printer_device_added (const char *udi, const char *capability GNUC_UNUSED)
02943 {
02944 if (config.autoprinter) {
02945 gvm_run_printer (udi);
02946 return TRUE;
02947 }
02948
02949 return FALSE;
02950 }
02951
02952 static gboolean
02953 scanner_device_added (const char *udi, const char *capability GNUC_UNUSED)
02954 {
02955 if (config.autoscanner) {
02956 gvm_run_scanner (udi);
02957 return TRUE;
02958 }
02959
02960 return FALSE;
02961 }
02962
02963 static gboolean
02964 webcam_device_added (const char *udi, const char *capability GNUC_UNUSED)
02965 {
02966 if (config.autowebcam) {
02967 gvm_run_webcam (udi);
02968 return TRUE;
02969 }
02970
02971 return FALSE;
02972 }
02973
02974
02975 static struct {
02976 const char *capability;
02977 DeviceAddedHandler handler;
02978 } devices[] = {
02979 #ifdef ENABLE_AUTOMOUNT
02980 { "block", block_device_added },
02981 #endif
02982 { "camera", camera_device_added },
02983
02984 { "input.keyboard", input_device_added },
02985 { "input.mouse", input_device_added },
02986 { "input.tablet", input_device_added },
02987 { "pda", pda_device_added },
02988 { "portable_audio_player", media_player_device_added },
02989 { "printer", printer_device_added },
02990 { "scanner", scanner_device_added },
02991 { "video4linux", webcam_device_added },
02992 };
02993
02994
02995
02996
02997
02998
02999 static void
03000 hal_device_added (LibHalContext *ctx GNUC_UNUSED,
03001 const char *udi)
03002 {
03003 char **capabilities;
03004 size_t i, j, n;
03005
03006 if (!gvm_user_is_active ())
03007 return;
03008
03009 dbg ("Device added: %s\n", udi);
03010
03011 if (!(capabilities = libhal_device_get_property_strlist (hal_ctx, udi, "info.capabilities", NULL)))
03012 return;
03013
03014 for (n = 0; capabilities[n]; n++)
03015 ;
03016
03017 qsort (capabilities, n, sizeof (char *), strptrcmp);
03018
03019 for (i = 0, j = 0; i < G_N_ELEMENTS (devices) && j < n; i++) {
03020 int cmp = -1;
03021
03022 while (j < n && (cmp = strcmp (capabilities[j], devices[i].capability)) < 0)
03023 j++;
03024
03025 if (cmp == 0) {
03026 if (devices[i].handler (udi, capabilities[j]))
03027 break;
03028 j++;
03029 }
03030 }
03031
03032 libhal_free_string_array (capabilities);
03033 }
03034
03035
03036
03037
03038
03039
03040 static void
03041 hal_device_removed (LibHalContext *ctx GNUC_UNUSED, const char *udi)
03042 {
03043 GtkDialog *dialog;
03044 #ifdef ENABLE_AUTOMOUNT
03045 char *device_udi;
03046 #endif
03047
03048 dbg ("Device removed: %s\n", udi);
03049
03050 #ifdef ENABLE_AUTOMOUNT
03051
03052 if ((device_udi = g_hash_table_lookup (device_table, udi))) {
03053 if (gvm_device_unmount (device_udi)) {
03054 GSList *l, *n;
03055
03056 for (l = mounted_volumes; l != NULL; l = n) {
03057 n = l->next;
03058 if (strcmp (udi, (const char *) l->data) == 0) {
03059 g_free (l->data);
03060 mounted_volumes = g_slist_delete_link (mounted_volumes, l);
03061 break;
03062 }
03063 }
03064 }
03065 }
03066 #endif
03067
03068 if ((dialog = g_hash_table_lookup (dialogs, udi)))
03069 gtk_dialog_response (dialog, GTK_RESPONSE_CANCEL);
03070 }
03071
03072
03073
03074
03075
03076
03077
03078 static void
03079 hal_device_new_capability (LibHalContext *ctx GNUC_UNUSED,
03080 const char *udi GNUC_UNUSED,
03081 const char *capability GNUC_UNUSED)
03082 {
03083 }
03084
03085
03086
03087
03088
03089
03090
03091 static void
03092 hal_device_lost_capability (LibHalContext *ctx GNUC_UNUSED,
03093 const char *udi GNUC_UNUSED,
03094 const char *capability GNUC_UNUSED)
03095 {
03096 }
03097
03098
03099
03100
03101
03102
03103
03104
03105 static void
03106 hal_property_modified (LibHalContext *ctx GNUC_UNUSED,
03107 const char *udi,
03108 const char *key,
03109 dbus_bool_t is_removed GNUC_UNUSED,
03110 dbus_bool_t is_added GNUC_UNUSED)
03111 {
03112 #ifdef ENABLE_AUTOMOUNT
03113 struct _MountPolicy *policy;
03114 #endif
03115 gboolean mounted;
03116 #ifdef ENABLE_AUTOMOUNT
03117 GSList *l, *n;
03118 #endif
03119
03120 if (strcmp (key, "volume.is_mounted") != 0)
03121 return;
03122
03123 mounted = libhal_device_get_property_bool (hal_ctx, udi, key, NULL);
03124
03125 if (mounted) {
03126 dbg ("Mounted: %s\n", udi);
03127
03128 #ifdef ENABLE_AUTOMOUNT
03129 if ((policy = g_hash_table_lookup (mount_table, udi))) {
03130 char *device;
03131
03132 g_hash_table_remove (mount_table, udi);
03133
03134
03135 mounted_volumes = g_slist_append (mounted_volumes, g_strdup (udi));
03136
03137 if ((device = libhal_device_get_property_string (hal_ctx, udi, "block.storage_device", NULL)))
03138 g_hash_table_insert (device_table, g_strdup (udi), device);
03139
03140 if (policy->apply)
03141 gvm_device_mounted (udi);
03142
03143 g_free (policy->udi);
03144 g_free (policy);
03145 } else if (gvm_user_is_active ()) {
03146 dbg ("not in mount queue: %s\n", udi);
03147
03148 }
03149 #else
03150 gvm_device_mounted (udi);
03151 #endif
03152
03153 #ifdef ENABLE_NOTIFY
03154 statfs_mount_info_add (udi);
03155 #endif
03156 } else {
03157 dbg ("Unmounted: %s\n", udi);
03158
03159 #ifdef ENABLE_NOTIFY
03160
03161 statfs_mount_info_remove (udi);
03162 #endif
03163
03164 #ifdef ENABLE_AUTOMOUNT
03165 g_hash_table_remove (device_table, udi);
03166
03167
03168 for (l = mounted_volumes; l != NULL; l = n) {
03169 n = l->next;
03170 if (strcmp (udi, (const char *) l->data) == 0) {
03171 g_free (l->data);
03172 mounted_volumes = g_slist_delete_link (mounted_volumes, l);
03173 break;
03174 }
03175 }
03176 #endif
03177 }
03178 }
03179
03180 #ifdef ENABLE_AUTOMOUNT
03181 static void
03182 gvm_device_eject (const char *udi)
03183 {
03184 char *storage, **volumes = NULL;
03185 DBusMessage *dmesg, *reply;
03186 const char *volume = udi;
03187 char **options = NULL;
03188 DBusError error;
03189 char *command;
03190 int i, n;
03191
03192 if (!libhal_device_get_property_bool (hal_ctx, udi, "block.is_volume", NULL)) {
03193 dbus_error_init (&error);
03194 volumes = libhal_find_device_by_capability (hal_ctx, "volume", &n, &error);
03195 if (dbus_error_is_set (&error)) {
03196 dbus_error_free (&error);
03197 return;
03198 }
03199
03200 volume = NULL;
03201 for (i = 0; i < n; i++) {
03202 volume = volumes[i];
03203
03204 if (!(storage = libhal_device_get_property_string (hal_ctx, volume, "info.parent", NULL)))
03205 continue;
03206
03207 if (!strcmp (udi, storage)) {
03208 libhal_free_string (storage);
03209 break;
03210 }
03211
03212 libhal_free_string (storage);
03213 }
03214 }
03215
03216 dbg ("ejecting %s...\n", volume);
03217
03218 if (!gnome_mount || access (gnome_mount, F_OK | R_OK | X_OK) != 0) {
03219 g_free (gnome_mount);
03220 gnome_mount = g_find_program_in_path ("gnome-mount");
03221 }
03222
03223 if (gnome_mount != NULL) {
03224 command = g_strdup_printf ("%s --eject --hal-udi=%%h", gnome_mount);
03225 gvm_run_command (command, volume, NULL, NULL);
03226 g_free (command);
03227 } else {
03228 if (!(dmesg = dbus_message_new_method_call ("org.freedesktop.Hal", volume,
03229 "org.freedesktop.Hal.Device.Volume",
03230 "Eject"))) {
03231 goto done;
03232 }
03233
03234 if (!dbus_message_append_args (dmesg, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &options, 0,
03235 DBUS_TYPE_INVALID)) {
03236 dbg ("eject failed for %s: could not append args to dbus message\n", udi);
03237 dbus_message_unref (dmesg);
03238 goto done;
03239 }
03240
03241 dbus_error_init (&error);
03242 if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, dmesg, -1, &error))) {
03243 dbg ("eject failed for %s: %s\n", volume, error.message);
03244 dbus_message_unref (dmesg);
03245 dbus_error_free (&error);
03246 goto done;
03247 }
03248
03249 dbus_message_unref (dmesg);
03250 dbus_message_unref (reply);
03251 }
03252
03253 done:
03254
03255 if (volumes)
03256 libhal_free_string_array (volumes);
03257 }
03258
03259
03260
03261
03262
03263
03264
03265
03266
03267 static void
03268 hal_device_condition (LibHalContext *ctx GNUC_UNUSED,
03269 const char *udi, const char *condition_name,
03270 const char *condition_details GNUC_UNUSED)
03271 {
03272 if (!gvm_user_is_active ())
03273 return;
03274
03275 if (!strcmp (condition_name, "EjectPressed"))
03276 gvm_device_eject (udi);
03277 }
03278 #endif
03279
03280 static gboolean
03281 reinit_dbus (gpointer user_data GNUC_UNUSED)
03282 {
03283 if (gvm_dbus_init ()) {
03284
03285 if ((hal_ctx = gvm_hal_init ()))
03286 libhal_ctx_set_dbus_connection (hal_ctx, dbus_connection);
03287 else
03288 exit (1);
03289
03290 return FALSE;
03291 }
03292
03293
03294
03295 return TRUE;
03296 }
03297
03298 static DBusHandlerResult
03299 gvm_dbus_filter_function (DBusConnection *connection GNUC_UNUSED, DBusMessage *message, void *user_data GNUC_UNUSED)
03300 {
03301 if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
03302 strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) {
03303 libhal_ctx_free (hal_ctx);
03304 hal_ctx = NULL;
03305
03306 dbus_connection_unref (dbus_connection);
03307 dbus_connection = NULL;
03308
03309 g_timeout_add (3000, reinit_dbus, NULL);
03310
03311 return DBUS_HANDLER_RESULT_HANDLED;
03312 }
03313
03314 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
03315 }
03316
03317 static gboolean
03318 gvm_dbus_init (void)
03319 {
03320 DBusError error;
03321
03322 if (dbus_connection != NULL)
03323 return TRUE;
03324
03325 dbus_error_init (&error);
03326 if (!(dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error))) {
03327 dbg ("could not get system bus: %s\n", error.message);
03328 dbus_error_free (&error);
03329 return FALSE;
03330 }
03331
03332 dbus_connection_setup_with_g_main (dbus_connection, NULL);
03333 dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
03334
03335 dbus_connection_add_filter (dbus_connection, gvm_dbus_filter_function, NULL, NULL);
03336
03337 return TRUE;
03338 }
03339
03340
03341 static void
03342 gvm_hal_claim_branch (const char *udi)
03343 {
03344 const char *claimed_by = "gnome-volume-manager";
03345 DBusMessage *dmesg, *reply;
03346 DBusError error;
03347
03348 if (!(dmesg = dbus_message_new_method_call ("org.freedesktop.Hal",
03349 "/org/freedesktop/Hal/Manager",
03350 "org.freedesktop.Hal.Manager",
03351 "ClaimBranch"))) {
03352 return;
03353 }
03354
03355 if (!dbus_message_append_args (dmesg, DBUS_TYPE_STRING, &udi, DBUS_TYPE_STRING, &claimed_by,
03356 DBUS_TYPE_INVALID)) {
03357 dbus_message_unref (dmesg);
03358 return;
03359 }
03360
03361 dbus_error_init (&error);
03362 if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, dmesg, -1, &error))) {
03363 dbus_message_unref (dmesg);
03364 dbus_error_free (&error);
03365 return;
03366 }
03367
03368 dbus_message_unref (dmesg);
03369 dbus_message_unref (reply);
03370 }
03371
03372
03373
03374
03375
03376
03377
03378 static LibHalContext *
03379 gvm_hal_init (void)
03380 {
03381 LibHalContext *ctx;
03382 DBusError error;
03383 char **devices;
03384 int nr;
03385
03386 if (!gvm_dbus_init ())
03387 return NULL;
03388
03389 if (!(ctx = libhal_ctx_new ())) {
03390 warn ("failed to create a HAL context!");
03391 return NULL;
03392 }
03393
03394 libhal_ctx_set_dbus_connection (ctx, dbus_connection);
03395
03396 libhal_ctx_set_device_added (ctx, hal_device_added);
03397 libhal_ctx_set_device_removed (ctx, hal_device_removed);
03398 libhal_ctx_set_device_new_capability (ctx, hal_device_new_capability);
03399 libhal_ctx_set_device_lost_capability (ctx, hal_device_lost_capability);
03400 libhal_ctx_set_device_property_modified (ctx, hal_property_modified);
03401 #ifdef ENABLE_AUTOMOUNT
03402 libhal_ctx_set_device_condition (ctx, hal_device_condition);
03403 #endif
03404
03405 dbus_error_init (&error);
03406 if (!libhal_device_property_watch_all (ctx, &error)) {
03407 warn ("failed to watch all HAL properties: %s", error.message ? error.message : "unknown");
03408 dbus_error_free (&error);
03409 libhal_ctx_free (ctx);
03410 return NULL;
03411 }
03412
03413 if (!libhal_ctx_init (ctx, &error)) {
03414 warn ("libhal_ctx_init failed: %s", error.message ? error.message : "unknown");
03415 dbus_error_free (&error);
03416 libhal_ctx_free (ctx);
03417 return NULL;
03418 }
03419
03420
03421
03422
03423
03424
03425
03426 if (!(devices = libhal_get_all_devices (ctx, &nr, &error))) {
03427 warn ("seems that HAL is not running: %s", error.message ? error.message : "unknown");
03428 dbus_error_free (&error);
03429
03430 libhal_ctx_shutdown (ctx, NULL);
03431 libhal_ctx_free (ctx);
03432 return NULL;
03433 }
03434
03435 libhal_free_string_array (devices);
03436
03437 gvm_hal_claim_branch ("/org/freedesktop/Hal/devices/local");
03438
03439 return ctx;
03440 }
03441
03442
03443 #ifdef ENABLE_AUTOMOUNT
03444
03445
03446
03447
03448 static void
03449 mount_all (LibHalContext *ctx)
03450 {
03451 char *prop, *dev, *udi, *drive;
03452 int num_volumes, mount;
03453 char **volumes;
03454 DBusError error;
03455 int i;
03456
03457 if (!config.automount_media)
03458 return;
03459
03460 dbus_error_init (&error);
03461 volumes = libhal_find_device_by_capability (ctx, "volume", &num_volumes, &error);
03462 if (dbus_error_is_set (&error)) {
03463 warn ("mount_all: could not find volume devices: %s", error.message);
03464 dbus_error_free (&error);
03465 return;
03466 }
03467
03468 for (i = 0; i < num_volumes; i++) {
03469 udi = volumes[i];
03470
03471 if (gvm_udi_is_subfs_mount (udi)) {
03472 #ifdef ENABLE_NOTIFY
03473 statfs_mount_info_add (udi);
03474 #endif
03475
03476
03477 if ((dev = libhal_device_get_property_string (ctx, udi, "block.storage_device", NULL)))
03478 g_hash_table_insert (device_table, g_strdup (udi), dev);
03479
03480 continue;
03481 }
03482
03483
03484 if (!libhal_device_property_exists (ctx, udi, "volume.is_mounted", NULL)
03485 || libhal_device_get_property_bool (ctx, udi, "volume.is_mounted", NULL)) {
03486 #ifdef ENABLE_NOTIFY
03487 statfs_mount_info_add (udi);
03488 #endif
03489 continue;
03490 }
03491
03492
03493 if (!libhal_device_property_exists (ctx, udi, "volume.fsusage", NULL))
03494 continue;
03495 prop = libhal_device_get_property_string (ctx, udi, "volume.fsusage", NULL);
03496 if (!prop || ((strcmp (prop, "filesystem") != 0) && (strcmp (prop, "crypto") != 0))) {
03497 libhal_free_string (prop);
03498 continue;
03499 }
03500 libhal_free_string (prop);
03501
03502
03503 if (!(drive = libhal_device_get_property_string (ctx, udi, "info.parent", NULL)))
03504 continue;
03505
03506 if (libhal_device_property_exists (ctx, drive, "storage.hotpluggable", NULL)
03507 && libhal_device_get_property_bool (ctx, drive, "storage.hotpluggable", NULL))
03508 mount = config.automount_drives;
03509 else if (libhal_device_property_exists (ctx, drive, "storage.removable", NULL)
03510 && libhal_device_get_property_bool (ctx, drive, "storage.removable", NULL))
03511 mount = config.automount_media;
03512 else
03513 mount = !libhal_device_get_property_bool (ctx, udi, "volume.ignore", NULL) &&
03514 libhal_device_get_property_bool (ctx, drive, "storage.automount_enabled_hint", NULL);
03515
03516 libhal_free_string (drive);
03517
03518 if (!mount)
03519 continue;
03520
03521
03522 if ((dev = libhal_device_get_property_string (ctx, udi, "block.device", &error))) {
03523 dbg ("mount_all: mounting %s\n", dev);
03524
03525 gvm_device_mount (udi, FALSE);
03526 libhal_free_string (dev);
03527 } else {
03528 warn ("mount_all: no device for udi=%s: %s", udi, error.message);
03529 if (dbus_error_is_set (&error))
03530 dbus_error_free (&error);
03531 }
03532 }
03533
03534 libhal_free_string_array (volumes);
03535 }
03536
03537
03538
03539
03540
03541
03542 static void
03543 unmount_all (void)
03544 {
03545 GSList *l;
03546
03547 dbg ("unmounting all volumes that we mounted in our lifetime\n");
03548
03549 for (l = mounted_volumes; l != NULL; l = l->next) {
03550 const char *udi = l->data;
03551
03552 dbg ("unmount_all: unmounting %s...\n", udi);
03553 gvm_device_unmount (udi);
03554 }
03555 }
03556 #endif
03557
03558
03559 static int sigterm_unix_signal_pipe_fds[2];
03560 static GIOChannel *sigterm_iochn;
03561
03562 static void
03563 handle_sigterm (int value GNUC_UNUSED)
03564 {
03565 static char marker[1] = {'S'};
03566
03567
03568
03569
03570
03571
03572
03573 write (sigterm_unix_signal_pipe_fds[1], marker, 1);
03574 }
03575
03576 static gboolean
03577 sigterm_iochn_data (GIOChannel *source,
03578 GIOCondition condition GNUC_UNUSED,
03579 gpointer user_data GNUC_UNUSED)
03580 {
03581 GError *err = NULL;
03582 gchar data[1];
03583 gsize bytes_read;
03584
03585
03586 if (G_IO_STATUS_NORMAL != g_io_channel_read_chars (source, data, 1, &bytes_read, &err)) {
03587 warn ("Error emptying callout notify pipe: %s", err->message);
03588 g_error_free (err);
03589 goto out;
03590 }
03591
03592 dbg ("Received SIGTERM, initiating shutdown\n");
03593
03594 #ifdef ENABLE_AUTOMOUNT
03595 unmount_all ();
03596 #endif
03597
03598 gtk_main_quit ();
03599
03600 out:
03601 return TRUE;
03602 }
03603
03604
03605 #ifdef ENABLE_NOTIFY
03606 static void
03607 statfs_mount_info_add (const char *udi)
03608 {
03609 statfs_mount_info *info;
03610
03611 if (g_hash_table_lookup (statfs_mounts, udi))
03612 return;
03613
03614 if (libhal_device_get_property_bool (hal_ctx, udi, "volume.is_mounted_read_only", NULL))
03615 return;
03616
03617
03618 if (gvm_udi_is_cdrom (udi))
03619 return;
03620
03621 info = g_new0 (statfs_mount_info, 1);
03622 info->udi = g_strdup (udi);
03623 info->notified = FALSE;
03624 info->last_notified = 0.0;
03625
03626 g_hash_table_insert (statfs_mounts, info->udi, info);
03627
03628 gvm_statfs_check_space (info->udi, info, NULL);
03629 }
03630
03631 static void
03632 statfs_mount_info_remove (const char *udi)
03633 {
03634 statfs_mount_info *info;
03635
03636 if ((info = g_hash_table_lookup (statfs_mounts, udi))) {
03637 g_hash_table_remove (statfs_mounts, udi);
03638 statfs_mount_info_free (info);
03639 }
03640 }
03641
03642 static void
03643 statfs_mount_info_free (statfs_mount_info *info)
03644 {
03645 g_free (info->udi);
03646 g_free (info);
03647 }
03648
03649 static gboolean
03650 gvm_statfs_check_space (const char *udi, statfs_mount_info *info, gpointer user_data GNUC_UNUSED)
03651 {
03652 char *mount_point = NULL;
03653 NotifyNotification *n;
03654 struct statvfs buf;
03655
03656 if (!(mount_point = libhal_device_get_property_string (hal_ctx, udi, "volume.mount_point", NULL)))
03657 return TRUE;
03658
03659 if (statvfs (mount_point, &buf) != -1) {
03660 unsigned long twogb_blocks;
03661 double free_space;
03662
03663 free_space = (double) buf.f_bavail / (double) buf.f_blocks;
03664 twogb_blocks = (2 * 1024 * 1024) / buf.f_bsize;
03665
03666
03667
03668
03669
03670 if ((info->last_notified - free_space) > config.percent_used
03671 || (free_space < config.percent_threshold && info->last_notified > config.percent_threshold))
03672 info->notified = FALSE;
03673
03674
03675
03676
03677
03678
03679 if (!info->notified && (free_space < config.percent_threshold && buf.f_bavail < twogb_blocks)) {
03680 char *disk, *label, *msg, *icon;
03681 int in_use;
03682
03683 label = libhal_device_get_property_string (hal_ctx, udi, "volume.label", NULL);
03684 if (!label || label[0] == '\0' || !strcmp (label, mount_point))
03685 disk = g_strdup (mount_point);
03686 else
03687 disk = g_strdup_printf ("%s (%s)", label, mount_point);
03688 libhal_free_string (label);
03689
03690 in_use = 100 - (free_space * 100);
03691
03692 if (!strcmp (disk, "/"))
03693 msg = g_strdup_printf (_("%d%% of the disk space on the root partition is in use"), in_use);
03694 else
03695 msg = g_strdup_printf (_("%d%% of the disk space on `%s' is in use"), in_use, disk);
03696 g_free (disk);
03697
03698 icon = libhal_device_get_property_string (hal_ctx, udi, "info.icon_name", NULL);
03699 if (icon != NULL)
03700 n = notify_notification_new (_("Low Disk Space"), msg, icon, NULL);
03701 else
03702 n = notify_notification_new (_("Low Disk Space"), msg, "drive-harddisk", NULL);
03703
03704 notify_notification_set_urgency (n, NOTIFY_URGENCY_CRITICAL);
03705 notify_notification_show (n, NULL);
03706 g_object_unref (n);
03707 g_free (msg);
03708
03709 info->notified = TRUE;
03710 info->last_notified = free_space;
03711 }
03712 }
03713
03714 libhal_free_string (mount_point);
03715
03716 return TRUE;
03717 }
03718
03719 static gboolean
03720 gvm_statfs_timeout (gpointer user_data GNUC_UNUSED)
03721 {
03722 g_hash_table_foreach (statfs_mounts, (GHFunc) gvm_statfs_check_space, NULL);
03723
03724 return TRUE;
03725 }
03726 #endif
03727
03728 static void
03729 gvm_die (GnomeClient *client GNUC_UNUSED,
03730 gpointer user_data GNUC_UNUSED)
03731 {
03732 dbg ("Received 'die', initiating shutdown\n");
03733
03734 #ifdef ENABLE_AUTOMOUNT
03735 unmount_all ();
03736 #endif
03737
03738 gtk_main_quit ();
03739 }
03740
03741
03742 #ifdef __linux__
03743 enum {
03744 LOCAL_USER_CHECKED = (1 << 0),
03745 LOCAL_USER_FOUND = (1 << 1)
03746 };
03747
03748
03749 static gboolean
03750 gvm_user_is_local_fallback (void)
03751 {
03752 static guint local = 0;
03753 struct dirent *dent;
03754 struct utmp *utmp;
03755 const char *user;
03756 char *vtend;
03757 size_t n;
03758 DIR *dir;
03759 int vt;
03760
03761 if (local & LOCAL_USER_CHECKED)
03762 return (local & LOCAL_USER_FOUND);
03763
03764 user = g_get_user_name ();
03765 n = strlen (user);
03766
03767 if (!(dir = opendir (GVM_CONSOLE_AUTH_DIR)))
03768 goto fallback;
03769
03770
03771 while ((dent = readdir (dir))) {
03772 if (!strncmp (user, dent->d_name, n)
03773 && (dent->d_name[n] == '\0'
03774 || (dent->d_name[n] == ':'
03775 && ((vt = strtol (dent->d_name + n + 1, &vtend, 10)) >= 0)
03776 && *vtend == '\0'))) {
03777 local = LOCAL_USER_FOUND;
03778 break;
03779 }
03780 }
03781
03782 closedir (dir);
03783
03784 fallback:
03785
03786 if (!(local & LOCAL_USER_FOUND)) {
03787 setutent ();
03788
03789 while (!(local & LOCAL_USER_FOUND) && (utmp = getutent ())) {
03790 if (utmp->ut_type != USER_PROCESS || strncmp (utmp->ut_user, user, n) != 0)
03791 continue;
03792
03793
03794 local = (utmp->ut_line[0] == ':' && utmp->ut_line[1] >= '0' && utmp->ut_line[1] <= '9')
03795 || !strncmp (utmp->ut_line, "tty", 3) ? LOCAL_USER_FOUND : 0;
03796 }
03797
03798 endutent ();
03799 }
03800
03801 local |= LOCAL_USER_CHECKED;
03802
03803 return (local & LOCAL_USER_FOUND);
03804 }
03805 #endif
03806
03807
03808 static GPtrArray *
03809 gvm_console_kit_get_seats (void)
03810 {
03811 DBusMessage *dmesg, *reply;
03812 DBusMessageIter iter, elem;
03813 GPtrArray *seats = NULL;
03814 DBusError error;
03815 char *path;
03816
03817 if (!(dmesg = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
03818 "/org/freedesktop/ConsoleKit/Manager",
03819 "org.freedesktop.ConsoleKit.Manager",
03820 "GetSeats"))) {
03821 dbg ("failed to create ConsoleKit.Manager request\n");
03822 return NULL;
03823 }
03824
03825 dbus_error_init (&error);
03826 if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, dmesg, -1, &error))) {
03827 dbg ("ConsoleKit.GetSeats request failed to reply\n");
03828 dbus_message_unref (dmesg);
03829 dbus_error_free (&error);
03830 return NULL;
03831 }
03832
03833 dbus_message_unref (dmesg);
03834
03835 dbus_message_iter_init (reply, &iter);
03836 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY ||
03837 dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_OBJECT_PATH) {
03838 dbg ("Unrecognized response to ConsoleKit.GetSeats request\n");
03839 dbus_message_unref (reply);
03840 return NULL;
03841 }
03842
03843 dbus_message_iter_recurse (&iter, &elem);
03844
03845 seats = g_ptr_array_new ();
03846
03847 do {
03848 if (dbus_message_iter_get_arg_type (&elem) == DBUS_TYPE_OBJECT_PATH) {
03849 dbus_message_iter_get_basic (&elem, &path);
03850 g_ptr_array_add (seats, g_strdup (path));
03851 }
03852 } while (dbus_message_iter_next (&elem));
03853
03854 dbus_message_unref (reply);
03855
03856 return seats;
03857 }
03858
03859 static GPtrArray *
03860 gvm_console_kit_seat_get_sessions (const char *seat_id)
03861 {
03862 DBusMessage *dmesg, *reply;
03863 DBusMessageIter iter, elem;
03864 GPtrArray *sessions = NULL;
03865 DBusError error;
03866 char *path;
03867
03868 if (!(dmesg = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", seat_id,
03869 "org.freedesktop.ConsoleKit.Seat",
03870 "GetSessions"))) {
03871 dbg ("failed to create ConsoleKit GetSessions request\n");
03872 return NULL;
03873 }
03874
03875 dbus_error_init (&error);
03876 if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, dmesg, -1, &error))) {
03877 dbg ("ConsoleKit GetSessions request failed to reply\n");
03878 dbus_message_unref (dmesg);
03879 dbus_error_free (&error);
03880 return NULL;
03881 }
03882
03883 dbus_message_unref (dmesg);
03884
03885 dbus_message_iter_init (reply, &iter);
03886 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY ||
03887 dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_OBJECT_PATH) {
03888 dbg ("Unrecognized response to ConsoleKit GetSessions request\n");
03889 dbus_message_unref (reply);
03890 return NULL;
03891 }
03892
03893 dbus_message_iter_recurse (&iter, &elem);
03894
03895 sessions = g_ptr_array_new ();
03896
03897 do {
03898 if (dbus_message_iter_get_arg_type (&elem) == DBUS_TYPE_OBJECT_PATH) {
03899 dbus_message_iter_get_basic (&elem, &path);
03900 g_ptr_array_add (sessions, g_strdup (path));
03901 }
03902 } while (dbus_message_iter_next (&elem));
03903
03904 dbus_message_unref (reply);
03905
03906 return sessions;
03907 }
03908
03909 static gboolean
03910 gvm_console_kit_session_get_uid (const char *session_id, uid_t *uid)
03911 {
03912 DBusMessage *dmesg, *reply;
03913 DBusMessageIter iter;
03914 DBusError error;
03915
03916 if (!(dmesg = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", session_id,
03917 "org.freedesktop.ConsoleKit.Session",
03918 "GetUnixUser"))) {
03919 dbg ("failed to create ConsoleKit GetUnixUser request\n");
03920 return FALSE;
03921 }
03922
03923 dbus_error_init (&error);
03924 if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, dmesg, -1, &error))) {
03925 dbg ("ConsoleKit GetUnixUser request failed to reply\n");
03926 dbus_message_unref (dmesg);
03927 dbus_error_free (&error);
03928 return FALSE;
03929 }
03930
03931 dbus_message_unref (dmesg);
03932
03933 dbus_message_iter_init (reply, &iter);
03934 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INT32) {
03935 dbg ("Unrecognized response to ConsoleKit GetUnixUser request\n");
03936 dbus_message_unref (reply);
03937 return FALSE;
03938 }
03939
03940 dbus_message_iter_get_basic (&iter, uid);
03941
03942 dbus_message_unref (reply);
03943
03944 return TRUE;
03945 }
03946
03947 static gboolean
03948 gvm_console_kit_session_get_bool (const char *session_id, const char *method, gboolean *value)
03949 {
03950 DBusMessage *dmesg, *reply;
03951 DBusMessageIter iter;
03952 DBusError error;
03953
03954 if (!(dmesg = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", session_id,
03955 "org.freedesktop.ConsoleKit.Session",
03956 method))) {
03957 dbg ("failed to create ConsoleKit %s request\n", method);
03958 return FALSE;
03959 }
03960
03961 dbus_error_init (&error);
03962 if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, dmesg, -1, &error))) {
03963 dbg ("ConsoleKit %s request failed to reply\n", method);
03964 dbus_message_unref (dmesg);
03965 dbus_error_free (&error);
03966 return FALSE;
03967 }
03968
03969 dbus_message_unref (dmesg);
03970
03971 dbus_message_iter_init (reply, &iter);
03972 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_BOOLEAN) {
03973 dbg ("Unrecognized response to ConsoleKit %s request\n", method);
03974 dbus_message_unref (reply);
03975 return FALSE;
03976 }
03977
03978 dbus_message_iter_get_basic (&iter, value);
03979
03980 dbus_message_unref (reply);
03981
03982 return TRUE;
03983 }
03984
03985 #define QUERY_BOOL(session, method, rv) gvm_console_kit_session_get_bool (session, method, rv)
03986
03987 enum {
03988 USER_IS_LOCAL = 1 << 0,
03989 USER_IS_ACTIVE = 1 << 1,
03990 };
03991
03992 static int
03993 gvm_query_console_kit (guint32 query, guint32 *result)
03994 {
03995 GPtrArray *sessions, *seats = NULL;
03996 char *session_id, *seat_id;
03997 gboolean found = FALSE;
03998 gboolean rv;
03999 guint i, j;
04000 uid_t uid;
04001
04002 *result = 0;
04003
04004 if (!(seats = gvm_console_kit_get_seats ()))
04005 return -1;
04006
04007 for (i = 0; i < seats->len && !found; i++) {
04008 seat_id = seats->pdata[i];
04009
04010 sessions = gvm_console_kit_seat_get_sessions (seat_id);
04011 if (sessions != NULL) {
04012 for (j = 0; j < sessions->len && !found; j++) {
04013 session_id = sessions->pdata[j];
04014
04015 if (gvm_console_kit_session_get_uid (session_id, &uid) && uid == getuid ()) {
04016 if ((query & USER_IS_ACTIVE) && QUERY_BOOL (session_id, "IsActive", &rv) && rv)
04017 *result |= USER_IS_ACTIVE;
04018 if ((query & USER_IS_LOCAL) && QUERY_BOOL (session_id, "IsLocal", &rv) && rv)
04019 *result |= USER_IS_LOCAL;
04020 found = TRUE;
04021 }
04022
04023 g_free (session_id);
04024 }
04025
04026 for ( ; j < sessions->len; j++)
04027 g_free (sessions->pdata[j]);
04028
04029 g_ptr_array_free (sessions, TRUE);
04030 }
04031
04032 g_free (seat_id);
04033 }
04034
04035 for ( ; i < seats->len; i++)
04036 g_free (seats->pdata[i]);
04037
04038 g_ptr_array_free (seats, TRUE);
04039
04040 return 0;
04041 }
04042
04043 static gboolean
04044 gvm_user_is_local (void)
04045 {
04046 guint32 result = 0;
04047
04048 if (gvm_query_console_kit (USER_IS_LOCAL, &result) != -1)
04049 return (result & USER_IS_LOCAL);
04050
04051
04052 #ifdef __linux__
04053 return gvm_user_is_local_fallback ();
04054 #else
04055 return FALSE;
04056 #endif
04057 }
04058
04059
04060 static gboolean
04061 gvm_user_is_active (void)
04062 {
04063 #ifdef ENABLE_MULTIUSER
04064 guint32 result = 0;
04065
04066 if (gvm_query_console_kit (USER_IS_ACTIVE, &result) != -1)
04067 return (result & USER_IS_ACTIVE);
04068
04069
04070
04071 return TRUE;
04072 #else
04073
04074 return TRUE;
04075 #endif
04076 }
04077
04078
04079 static gboolean print_version = FALSE;
04080 static const char *daemon_arg = NULL;
04081 static gboolean no_daemon = FALSE;
04082 static gboolean secret_mode = FALSE;
04083
04084 static GOptionEntry options[] = {
04085 { "version", 'v', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_NONE, &print_version,
04086 N_("Print version and exit"), NULL },
04087 { "daemon", 'd', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_STRING, (char **) &daemon_arg,
04088 N_("Run as a daemon"), "<yes|no>" },
04089 { "no-daemon", 'n', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_NONE, &no_daemon,
04090 N_("Don't run as a daemon"), NULL },
04091 { "secret-mode", 's', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_NONE, &secret_mode,
04092 N_("Run in secret mode"), NULL },
04093 { NULL, '\0', 0, 0, NULL, NULL, NULL }
04094 };
04095
04096
04097 int
04098 main (int argc, char **argv)
04099 {
04100 gboolean daemonize = TRUE;
04101 GnomeProgram *program;
04102 GnomeClient *client;
04103 GOptionContext *ctx;
04104
04105 bindtextdomain (PACKAGE, GNOMELOCALEDIR);
04106 bind_textdomain_codeset (PACKAGE, "UTF-8");
04107 textdomain (PACKAGE);
04108
04109 ctx = g_option_context_new (PACKAGE);
04110 g_option_context_add_main_entries (ctx, options, NULL);
04111
04112 program = gnome_program_init (PACKAGE, VERSION, LIBGNOMEUI_MODULE, argc, argv,
04113 GNOME_PARAM_GOPTION_CONTEXT, ctx, GNOME_PARAM_NONE);
04114
04115 if (print_version) {
04116 fprintf (stdout, "%s version %s\n", PACKAGE, VERSION);
04117 exit (0);
04118 }
04119
04120 if (daemon_arg != NULL) {
04121 if (!strcmp (daemon_arg, "yes") || !strcmp (daemon_arg, "true"))
04122 daemonize = TRUE;
04123 else if (!strcmp (daemon_arg, "no") || !strcmp (daemon_arg, "false"))
04124 daemonize = FALSE;
04125 else
04126 fprintf (stdout, _("Unrecognized --daemon argument: %s\n"), daemon_arg);
04127 }
04128
04129 if (no_daemon)
04130 daemonize = FALSE;
04131
04132 if (secret_mode)
04133 fprintf (stdout, "Run silent, run deep.\n");
04134
04135 if (daemonize && daemon (0, 0) < 0) {
04136 warn ("daemonizing failed: %s", g_strerror (errno));
04137 return 1;
04138 }
04139
04140 client = gnome_master_client ();
04141 g_signal_connect (client, "die", G_CALLBACK (gvm_die), NULL);
04142
04143 if (!(hal_ctx = gvm_hal_init ()))
04144 return 1;
04145
04146 if (gvm_get_clipboard () && gvm_user_is_local ()) {
04147 gnome_client_set_restart_style (client, GNOME_RESTART_ANYWAY);
04148 } else {
04149 gnome_client_set_restart_style (client, GNOME_RESTART_NEVER);
04150 if (gvm_user_is_local ())
04151 warn ("already running");
04152
04153 return 1;
04154 }
04155
04156 gvm_init_config ();
04157
04158
04159 if (pipe (sigterm_unix_signal_pipe_fds) != 0) {
04160 warn ("Could not setup pipe, errno=%d", errno);
04161 return 1;
04162 }
04163
04164 sigterm_iochn = g_io_channel_unix_new (sigterm_unix_signal_pipe_fds[0]);
04165 if (sigterm_iochn == NULL) {
04166 warn ("Could not create GIOChannel");
04167 return 1;
04168 }
04169
04170 g_io_add_watch (sigterm_iochn, G_IO_IN, sigterm_iochn_data, NULL);
04171 signal (SIGTERM, handle_sigterm);
04172
04173 #ifdef ENABLE_AUTOMOUNT
04174 device_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
04175 (GDestroyNotify) libhal_free_string);
04176 mount_table = g_hash_table_new (g_str_hash, g_str_equal);
04177 #endif
04178
04179 dialogs = g_hash_table_new (g_str_hash, g_str_equal);
04180
04181 #ifdef ENABLE_NOTIFY
04182
04183 notify_init ("GNOME Volume Manager");
04184
04185
04186 statfs_mounts = g_hash_table_new (g_str_hash, g_str_equal);
04187 #endif
04188
04189 #ifdef ENABLE_AUTOMOUNT
04190 mount_all (hal_ctx);
04191 #endif
04192
04193 #ifdef ENABLE_NOTIFY
04194
04195 statfs_id = g_timeout_add (15000, (GSourceFunc) gvm_statfs_timeout, NULL);
04196 #endif
04197
04198 gtk_main ();
04199
04200 #ifdef ENABLE_NOTIFY
04201 g_hash_table_destroy (statfs_mounts);
04202 g_source_remove (statfs_id);
04203 statfs_id = 0;
04204 #endif
04205
04206 #ifdef ENABLE_AUTOMOUNT
04207 g_hash_table_destroy (device_table);
04208 g_hash_table_destroy (mount_table);
04209 #endif
04210
04211 g_object_unref (program);
04212
04213 return 0;
04214 }