/* $Id$ Copyright (C) 2003-2010 tooar Portions copyright (C) 1999 Michael Clark This file is part of emelFM2. emelFM2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. emelFM2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with emelFM2; see the file GPL. If not, see http://www.gnu.org/licenses. */ /** @file plugins/e2p_pack.c @brief plugin for interfacting with several archive managers, to pack selected item(s) */ #include "emelfm2.h" #include #include "e2_plugins.h" #include "e2_dialog.h" #include "e2_command.h" #include "e2_task.h" #include "e2_filelist.h" //same enum as in unpack plugin, though it need not be so enum { TAR_GZ, TAR_BZ2, TAR_LZMA, TAR_XZ, TAR, /*DEB, RPM, */ZIP, Z7Z, RAR, ARJ, ZOO, MAXTYPES }; typedef struct _E2_PackDlgRunTime { GtkWidget *dialog; GtkWidget *filename_entry; GtkWidget *pkgtype_combo; gchar *curr_dir; //utf8 form of qed->currdir (with trailer) } E2_PackDlgRunTime; static gint pkg_type = TAR_GZ; //in theory, we should protect this by mutex //these extension strings are in same order as enum static gchar *ext_str [MAXTYPES] = { ".tar.gz", ".tar.bz2", ".tar.lzma", ".tar.xz", ".tar", // ".deb", // ".rpm", ".zip", ".7z", ".rar", ".arj", ".zoo" }; static gboolean _e2p_packQ (E2_ActionTaskData *qed); /** @brief implement user's choice to pack the archive BGL on */ static void _e2p_pack_yes (E2_PackDlgRunTime *rt) { static gchar *cmd_str [MAXTYPES] = { //these command strings are in same order as enum //NOTE: %%f is converted to %f when the command is constructed with g_strdup_printf () ">tar cvf - %%f | gzip - > %s", //run in separate shell ">tar cvf - %%f | bzip2 - > %s",//ditto default block size -9 is not significantly better, maybe use -3 instead ? ">tar cvf - %%f | lzma - > %s", //ditto default compresssion -7, maybe use -2 instead ? ">tar cvf - %%f | xz - > %s", "tar cvf %s %%f", // FIXME deb pack command // FIXME rpm "pack" command does not exist. rpmbuild ? // "zip -r %s %%f", adds to any existing archive ">zip -r - %%f > %s", // "7za a -t7z %s %%f", adds to any existing archive ">7za a -t7z -so %%f > %s", //CHECKME "rar a -r -ol -tl %s %%f", // "arj a -a1 -r %s %%f", "arj a -a -r -s -2s %s %%f", //CHECKME "zoo ahP %s %%f" }; /* compress ANSI files: 7za a -tzip archive.zip file1 file2 ... fileN compress ANSI dir: 7za a -tzip archive.zip dirnametocompress\ compress UNICODE files: 7za a -t7z archive.7z file1 file2 ... fileN compress UNICODE dir: 7za a -t7z archive.7z dirnametocompress\ decompress ANSI: 7za x archive.zip -odirname -aoa decompress UNICODE: 7za x archive.7z -odirname -aoa */ pkg_type = gtk_combo_box_get_active (GTK_COMBO_BOX (rt->pkgtype_combo)); if (pkg_type != -1) { gchar *full_name; const gchar *chosen_name = gtk_entry_get_text (GTK_ENTRY (rt->filename_entry)); gboolean flag = (*chosen_name != '\0'); if (flag) { full_name = g_strconcat (chosen_name, ext_str [pkg_type], NULL); if (e2_option_bool_get ("confirm-overwrite")) { #ifdef E2_VFSTMP //FIXME dir when not mounted local #else gchar *utf = g_strconcat (rt->curr_dir, full_name, NULL); //separator comes with dir #endif gchar *dlocal = F_FILENAME_TO_LOCALE (utf); #ifdef E2_VFS VPATH ddata = { dlocal, NULL }; //running a command is only local if (e2_fs_access2 (&ddata E2_ERR_NONE()) == 0) #else if (e2_fs_access2 (dlocal E2_ERR_NONE()) == 0) #endif { //same-named item exists already //FIXME some apps allow addition to existing archive gdk_threads_leave (); DialogButtons result = e2_dialog_ow_check (NULL, #ifdef E2_VFS &ddata, #else dlocal, #endif NONE); gdk_threads_enter (); if (result != OK) { flag = FALSE; //signal that we will not proceed g_free (full_name); } } g_free (utf); F_FREE (dlocal, utf); } } if (flag) { //tag E2_BADQUOTES gchar *qp = e2_utils_quote_string (full_name); gchar *command = g_strdup_printf (cmd_str [pkg_type], qp); g_free (qp); // e2_filelist_disable_refresh (); //prevent changes to selected item data // gint res = e2_command_run (command, E2_COMMAND_RANGE_DEFAULT, rt->dialog #ifdef E2_COMMANDQ , FALSE #endif ); // e2_filelist_enable_refresh (); //probably nothing reported yet, to trigger a refresh // flag = (res == 0); g_free (full_name); g_free (command); } } else pkg_type = TAR_GZ; } /** @brief callback for dialog's "response" signal @param dialog the dialog where the response was triggered @param response the response for the clicked button @param rt pointer to data for dialog @return */ static void _e2p_pack_response_cb (GtkDialog *dialog, gint response, E2_PackDlgRunTime *rt) { switch (response) { case E2_RESPONSE_APPLY: gtk_widget_hide (rt->dialog); _e2p_pack_yes (rt); break; default: break; } gtk_widget_destroy (rt->dialog); g_free (rt->curr_dir); DEALLOCATE (E2_PackDlgRunTime, rt); } /** @brief handle activation ( keypresses) in the query entry @param entry UNUSED the entry widget for the combo box @param rt pointer to dialog data struct @return */ static void _e2p_pack_activated_cb (GtkEntry *entry, E2_PackDlgRunTime *rt) { _e2p_pack_response_cb (GTK_DIALOG (rt->dialog), E2_RESPONSE_APPLY, rt); } /** @brief create and run dialog @param from the button, menu item etc which was activated @param art action runtime data @return TRUE if action completed successfully, else FALSE */ static gboolean _e2p_pack (gpointer from, E2_ActionRuntime *art) { return (e2_task_enqueue_task (E2_TASK_PACK, art, from, _e2p_packQ, NULL)); } static gboolean _e2p_packQ (E2_ActionTaskData *qed) { E2_PackDlgRunTime *rt = ALLOCATE (E2_PackDlgRunTime); CHECKALLOCATEDWARNT (rt, return FALSE;) rt->dialog = e2_dialog_create (NULL, _("Filename:"), _("archive creation"), (ResponseFunc)_e2p_pack_response_cb, rt); GtkWidget *hbox = g_object_get_data (G_OBJECT (rt->dialog), "e2-dialog-hbox"); GPtrArray *names = qed->names; E2_SelectedItemInfo **iterator = (E2_SelectedItemInfo **) names->pdata; gchar *suggested_name = F_FILENAME_FROM_LOCALE ((*iterator)->filename); rt->filename_entry = e2_widget_add_entry (hbox, suggested_name, TRUE, TRUE); F_FREE (suggested_name, (*iterator)->filename); #ifdef E2_ASSISTED GtkWidget *label = (GtkWidget *) g_object_get_data (G_OBJECT (rt->dialog), "e2-dialog-label"); e2_widget_set_label_relations (label, rt->filename_entry); #endif g_signal_connect (G_OBJECT (rt->filename_entry), "activate", G_CALLBACK (_e2p_pack_activated_cb), rt); rt->pkgtype_combo = e2_combobox_add (hbox, FALSE, 0, NULL, NULL, NULL, E2_COMBOBOX_MENU_STYLE); //these applied package-extension strings are in same order as enum e2_combobox_append_history_counted (rt->pkgtype_combo, MAXTYPES, ext_str); gtk_combo_box_set_active (GTK_COMBO_BOX (rt->pkgtype_combo), pkg_type); rt->curr_dir = D_FILENAME_FROM_LOCALE (qed->currdir); E2_Button local_btn; e2_button_derive (&local_btn, &E2_BUTTON_APPLY, BTN_YES_CONTINUE); e2_dialog_show (rt->dialog, app.main_window, E2_DIALOG_CLOSELOCK, &E2_BUTTON_CANCEL, &local_btn, NULL); return TRUE; } //aname must be confined to this module static gchar *aname; /** @brief plugin initialization function, called by main program @param p ptr to plugin data struct @return TRUE if the initialization succeeds, else FALSE */ gboolean init_plugin (Plugin *p) { #define ANAME "pack" aname = _("pack"); p->signature = ANAME VERSION; p->menu_name = _("_Pack.."); p->description = _("Build an archive containing the selected item(s)"); p->icon = "plugin_"ANAME E2ICONTB; //use icon file pathname if appropriate if (p->action == NULL) { //don't free name string here E2_Action plugact = {g_strconcat (_A(6),".", aname, NULL),_e2p_pack,FALSE,E2_ACTION_TYPE_ITEM,0,NULL,NULL}; p->action = e2_plugins_action_register (&plugact); if G_LIKELY((p->action != NULL)) return TRUE; g_free (plugact.name); } return FALSE; } /** @brief cleanup transient things for this plugin @param p pointer to data struct for the plugin @return TRUE if all cleanups were completed */ gboolean clean_plugin (Plugin *p) { gchar *action_name = g_strconcat (_A(6),".",aname,NULL); gboolean ret = e2_plugins_action_unregister (action_name); g_free (action_name); return ret; }