/* Jungle Monkey
* Copyright (C) 1999-2001 The Regents of the University of Michigan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ggui_files.h"
#include "ggui.h"
#include "ggui_channels.h"
#include "ggui_chat.h"
#include "ggui_config.h"
#include "ggui_debug.h"
#include "ggui_download.h"
#include "ggui_properties.h"
#include "ggui_search.h"
#include "entry_dialog.h"
#include "pixmaps.h"
#include "util/util.h"
#include "util/jmgnet.h"
#include "util/sha_async.h"
#include "util/sha_cache.h"
#include <sys/types.h>
#include <dirent.h>
/* ******************** */
typedef struct _File
{
MtpLocalMirror* mirror;
GURL* url;
gchar* path;
GSHAAsyncID sha_id;
JMMSPVFSID* search_id;
GURL* channel; /* channel */
gchar* apath; /* path to announcement */
} File;
static GladeXML* menu_xml;
static GtkCList* files_clist;
static GtkWidget* files_popup;
static JMChannel* shown_channel;
static JMAnn* shown_ann;
static JMAnn* selected_ann;
static ShaCache* sha_cache;
static GHashTable* url_to_file;
static GHashTable* name_to_file;
enum {
DND_TARGET_STRING,
DND_TARGET_URI_LIST,
};
static GtkTargetEntry dnd_target_table[] = {
{ "text/uri-list", 0, DND_TARGET_URI_LIST },
{ "text/plain", 0, DND_TARGET_STRING },
{ "STRING", 0, DND_TARGET_STRING },
};
/* ******************** */
static void shutdown_hfunc (gpointer key, gpointer value, gpointer user_data);
static void load_file_func (const ElfNode* elf);
static void save_file_hfunc (gpointer key, gpointer value, gpointer user_data);
static gint jmann_compare (gconstpointer a, gconstpointer b);
static int get_order (const GURL* url);
static void add_file (const GURL* channel, const gchar* cpath, const gchar* path);
static void sha_cb (GSHA* sha, gpointer user_data);
static void add_url (const GURL* channel, const gchar* path, const gchar* name,
const GURL* url);
static gboolean create_dir (const GURL* channel, const gchar* path, const gchar* name);
static void add_dir (const GURL* channel, const gchar* cpath, const gchar* path);
static void add_file_r (const GURL* channel, const gchar* cpath, const gchar* path);
static void file_remove_r (const GURL* curl, JMAnn* ann);
static void file_add (File* file);
static void file_delete (File* file);
static File* file_get (const GURL* channel, const gchar* path);
static guint file_hash (gconstpointer p);
static gint file_equal (gconstpointer p1, gconstpointer p2);
void on_files_select_row (GtkCList* list, gint row, gint column, GdkEvent* event);
void on_files_unselect_row (GtkCList* list, gint row, gint column, GdkEvent* event);
gint on_files_button_press (GtkCList* list, GdkEventButton *event, gpointer user_data);
gboolean on_files_drag_motion (GtkCList* list, GdkDragContext* context,
gint x, gint y, guint time);
void on_files_drag_data_received (GtkCList* list, GdkDragContext* context,
gint x, gint y, GtkSelectionData* data,
guint info, guint time, gpointer user_data);
static void dnd_parse (gchar* buf, gint len);
#define POPUPFUNC(F) void F(void)
POPUPFUNC (on_files_get_file);
POPUPFUNC (on_files_cancel_download);
POPUPFUNC (on_files_remove_file);
POPUPFUNC (on_files_open_url);
POPUPFUNC (on_files_remove_url);
POPUPFUNC (on_files_join_channel);
POPUPFUNC (on_files_remove_channel);
POPUPFUNC (on_files_remove_sel_channel);
POPUPFUNC (on_files_leave_channel);
POPUPFUNC (on_files_join_chat);
POPUPFUNC (on_files_remove_chat);
POPUPFUNC (on_files_leave_chat);
POPUPFUNC (on_files_join_search);
POPUPFUNC (on_files_remove_search);
POPUPFUNC (on_files_leave_search);
POPUPFUNC (on_files_add_file);
POPUPFUNC (on_files_add_directory);
POPUPFUNC (on_files_add_url);
POPUPFUNC (on_files_create_chat);
POPUPFUNC (on_files_create_search);
POPUPFUNC (on_files_create_directory);
POPUPFUNC (on_files_create_channel);
POPUPFUNC (on_files_create_channel_from_directory);
POPUPFUNC (on_files_open_channel);
POPUPFUNC (on_files_create_root_channel);
POPUPFUNC (on_files_remove_current_channel);
POPUPFUNC (on_files_leave_current_channel);
POPUPFUNC (on_files_remove);
POPUPFUNC (on_files_properties);
typedef enum {
IT_CREATE_ROOT_CHANNEL,
IT_CREATE_CHANNEL,
IT_CREATE_CHANNEL_FROM_DIR,
IT_OPEN_CHANNEL,
IT_JOIN_CHANNEL,
IT_LEAVE_CHANNEL,
IT_LEAVE_CURRENT_CHANNEL,
IT_REMOVE_CHANNEL,
IT_REMOVE_CURRENT_CHANNEL,
IT_ADD_FILE,
IT_GET_FILE,
IT_CANCEL_DOWNLOAD,
IT_REMOVE_FILE,
IT_CREATE_DIR,
IT_ADD_DIR,
IT_GET_DIR,
IT_REMOVE_DIR,
IT_ADD_URL,
IT_OPEN_URL,
IT_REMOVE_URL,
IT_CREATE_CHAT,
IT_JOIN_CHAT,
IT_LEAVE_CHAT,
IT_REMOVE_CHAT,
IT_CREATE_SEARCH,
IT_JOIN_SEARCH,
IT_LEAVE_SEARCH,
IT_REMOVE_SEARCH,
IT_REMOVE,
IT_PROPERTIES,
IT_SEPARATOR1,
IT_SEPARATOR2,
IT_SEPARATOR3,
IT_EXIT
} Item;
static void toolbar_append (Item item, GdkPixmap* gpixmap, GdkBitmap* gbitmap,
const gchar* tooltip, void* func);
static void update_items (void* widget);
static void show_item (void* widget, Item it);
void
ggui_file_init (void)
{
menu_xml = ggui_get_glade_xml("files_popup", "master_popup.glade");
g_assert (menu_xml != NULL);
glade_xml_signal_autoconnect (menu_xml);
/* Get the widgets */
files_clist = GTK_CLIST(glade_xml_get_widget(jmw_xml, "files_clist"));
files_popup = GTK_WIDGET(glade_xml_get_widget(menu_xml, "files_popup"));
g_assert (files_clist != NULL);
g_assert (files_popup != NULL);
gtk_clist_column_title_passive (files_clist, 0);
gtk_clist_column_title_passive (files_clist, 1);
/* Set up tooltips */
ggui_set_tooltip (GTK_WIDGET(files_clist),
_("Files, directories, and channels available. "
"Right-click on something to get a popup-menu of options. "
"Double-click on something to activate it."));
/* Set up drop and drag */
gtk_drag_dest_set (GTK_WIDGET(files_clist),
GTK_DEST_DEFAULT_ALL,
dnd_target_table,
sizeof(dnd_target_table) / sizeof(dnd_target_table[0]),
GDK_ACTION_COPY /* | GDK_ACTION_MOVE */);
url_to_file = g_hash_table_new (gnet_url_hash, gnet_url_equal);
name_to_file = g_hash_table_new (file_hash, file_equal);
sha_cache = sha_cache_new ();
}
void
ggui_file_shutdown (void)
{
/* Reset vars */
shown_channel = NULL;
shown_ann = NULL;
selected_ann = NULL;
g_hash_table_destroy (url_to_file);
url_to_file = NULL;
/* Delete sha cache */
sha_cache_delete (sha_cache);
sha_cache = NULL;
/* Delete files */
g_hash_table_foreach (name_to_file, shutdown_hfunc, NULL);
g_hash_table_destroy (name_to_file);
name_to_file = NULL;
}
static void
shutdown_hfunc (gpointer key, gpointer value, gpointer user_data)
{
file_delete ((File*) value);
}
void
ggui_file_load (void)
{
gchar* sc_name;
FILE* sc_file;
g_return_if_fail (jm_btp_bpeer);
/* Load sha cache */
sc_name = g_strconcat (jm_config_home, G_DIR_SEPARATOR_S, "sha-cache", NULL);
sc_file = fopen (sc_name, "r");
if (sc_file)
{
sha_cache_read (sha_cache, sc_file);
fclose (sc_file);
}
g_free (sc_name);
ggui_load_elf ("file", load_file_func);
}
static void
load_file_func (const ElfNode* elf)
{
const gchar* curl_str;
GURL* curl = NULL;
const gchar* apath;
const gchar* url_str;
GURL* url = NULL;
const gchar* path;
File* file;
JMAnn* ann;
curl_str = elf_get_attribute (elf, "curl");
if (!curl_str) return;
curl = gnet_url_new (curl_str);
if (!curl) return;
apath = elf_get_attribute (elf, "apath");
if (!apath) goto done;
/* Clean URL */
if (!SAFESTRCMP(jm_hostname, curl->hostname) &&
(!jm_btp_last_port || curl->port == jm_btp_last_port))
gnet_url_set_port (curl, jm_btp_bpeer->port);
/* Ignore if we have */
if (file_get (curl, apath)) goto done;
url_str = elf_get_attribute (elf, "url");
if (url_str) url = gnet_url_new (url_str);
path = elf_get_attribute (elf, "path");
if (!strcmp (elf->name, "file") && path)
{
GURL* murl;
MtpLocalMirror* mirror;
GSHA* sha;
/* Ignore if files does not exist */
if (!file_exists(path))
goto done;
/* Make MTP */
murl = gnet_url_clone (jm_mtp_rvous_url);
gnet_url_set_resource (murl, apath);
mirror = mtp_mirror_path (jm_mtp_server, murl, path);
if (!mirror)
{
gnet_url_delete (murl);
goto done;
}
file = g_new0 (File, 1);
file->mirror = mirror;
file->path = g_strdup (path);
file->url = murl;
file->apath = g_strdup (apath);
file->channel = curl;
file->search_id = ggui_search_vfs_add (murl, g_basename(path), file_size (path));
file_add (file);
/* Get SHA and announce (or get sha asynchronously) */
sha = sha_cache_get (sha_cache, path);
if (sha)
{
GGUIP (8, "sha cache hit %s\n", path);
ggui_channel_add_path_sha (curl, apath, murl, sha);
gnet_sha_delete (sha);
}
else
file->sha_id = gnet_sha_new_file_async (path, sha_cb, file);
curl = NULL;
}
else if (!strcmp (elf->name, "url") && url)
{
ann = ggui_channel_add_path (curl, apath, url);
if (!ann) goto done;
file = g_new0 (File, 1);
file->url = url;
file->channel = curl; curl = NULL;
file->apath = g_strdup (apath);
file_add (file);
}
else if (!strcmp (elf->name, "dir"))
{
ann = ggui_channel_add_path (curl, apath, NULL);
if (!ann) goto done;
file = g_new0 (File, 1);
file->channel = curl; curl = NULL;
file->apath = g_strdup (apath);
file_add (file);
}
done:
gnet_url_delete (curl);
gnet_url_delete (url);
}
void
ggui_file_save (void)
{
gchar* sc_name;
FILE* sc_file;
/* Save sha cache */
sc_name = g_strconcat (jm_config_home, G_DIR_SEPARATOR_S, "sha-cache", NULL);
sc_file = fopen (sc_name, "w");
if (sc_file)
{
sha_cache_write (sha_cache, sc_file);
fclose (sc_file);
}
else
g_warning ("Can't open file %s/sha-cache\n", jm_config_home);
g_free (sc_name);
/* Save files */
ggui_save_hashtable ("file", name_to_file, save_file_hfunc);
}
static void
save_file_hfunc (gpointer key, gpointer value, gpointer user_data)
{
File* file = (File*) value;
FILE* File = (FILE*) user_data;
ElfNode* elf;
gchar* buf;
gint len;
gchar* curl;
g_return_if_fail (file->channel && file->apath);
elf = elf_new (NULL);
curl = gnet_url_get_nice_string (file->channel);
elf_set_attribute (elf, "curl", curl);
g_free (curl);
elf_set_attribute (elf, "apath", file->apath);
if (file->mirror)
{
elf_set_name (elf, "file");
elf_set_attribute (elf, "path", file->path);
}
else if (file->url)
{
gchar* url;
elf_set_name (elf, "url");
url = gnet_url_get_nice_string (file->url);
elf_set_attribute (elf, "url", url);
g_free (url);
}
else
{
elf_set_name (elf, "dir");
}
elf_write (elf, &buf, &len);
fwrite (buf, len, 1, File);
elf_delete (elf);
g_free (buf);
}
/* ********** */
static gint
jmann_compare (gconstpointer a, gconstpointer b)
{
const JMAnn* ann1 = (const JMAnn*) a;
const JMAnn* ann2 = (const JMAnn*) b;
gint order1, order2;
order1 = get_order (ann1->url);
order2 = get_order (ann2->url);
if (order1 < order2) return -1;
else if (order1 > order2) return 1;
return strcmp (ann1->name, ann2->name);
}
/* Order: channel (0), dir (1), chat(2), search(3), non-file (4), file (5) */
int
get_order (const GURL* url)
{
if (!url)
return 1;
else if (gnet_url_is_scheme (url, "jm"))
return 0;
else if (gnet_url_is_scheme (url, "jmchat"))
return 2;
else if (gnet_url_is_scheme (url, "jmmsp"))
return 3;
else if (gnet_url_is_scheme (url, "mtp"))
return 5;
return 4;
}
/* ******************** */
void
ggui_file_show (JMChannel* channel, JMAnn* ann)
{
GList* sorted;
GList* i;
g_return_if_fail ((channel && ann) || (!channel && !ann));
/* Ignore if we're already showing this */
if (channel == shown_channel && ann == shown_ann)
return;
GGUIP (8, "file_show %s %s\n", channel?jmchannel_get_name(channel):"<null>",
ann?ann->path:"<null>");
/* Reset selected_ann */
selected_ann = NULL;
/* Clear the list */
gtk_clist_clear (files_clist);
/* Set the shown channel/ann */
shown_channel = channel;
shown_ann = ann;
/* Update tool bar */
ggui_file_update_toolbar ();
/* We're done if the channel/ann is NULL */
if (!channel && !ann)
return;
gtk_clist_freeze (files_clist);
/* Add all children files */
sorted = g_list_copy (ann->kids);
sorted = g_list_sort (sorted, jmann_compare);
sorted = g_list_reverse (sorted);
for (i = sorted; i != NULL; i = i->next)
ggui_file_announce_update (channel, (JMAnn*) i->data);
g_list_free (sorted);
/* Add a back button if this has a parent */
if (ann->parent)
{
int row;
gchar* texts[2] = {NULL, NULL};
row = gtk_clist_prepend (files_clist, texts);
gtk_clist_set_row_data (files_clist, row, back_pixmap);
gtk_clist_set_pixtext (files_clist, row, 0, _(".."), 5,
back_pixmap, back_mask);
}
gtk_clist_thaw (files_clist);
}
void
ggui_file_get_shown (JMChannel** channelp, JMAnn** annp)
{
g_return_if_fail (channelp && annp);
*channelp = shown_channel;
*annp = shown_ann;
}
/* ******************** */
gboolean
ggui_file_have (const GURL* url)
{
return (g_hash_table_lookup(url_to_file, url) != NULL);
}
/* ******************** */
void
ggui_file_announce_update (JMChannel* channel, JMAnn* ann)
{
gint row;
GdkPixmap* pixmap;
GdkBitmap* mask;
gint percent = -1;
gint length;
gchar* text1 = NULL;
gchar* text2 = NULL;
g_return_if_fail (channel && ann);
/* Ignore if not shown */
if (channel != shown_channel || ann->parent != shown_ann)
return;
/* Ignore if an index file */
if (jmann_is_index (ann))
return;
/* Add to clist if not there */
row = gtk_clist_find_row_from_data (files_clist, ann);
if (row < 0)
{
gchar* texts[2] = {NULL, NULL};
/* Insert after back, if back, otherwise prepend */
if (gtk_clist_get_row_data(files_clist, 0) == back_pixmap)
row = gtk_clist_insert (files_clist, 1, texts);
else
row = gtk_clist_prepend (files_clist, texts);
gtk_clist_set_row_data (files_clist, row, ann);
}
/* Get download status */
if (ann->url)
percent = ggui_download_get_percent_complete(ann->url);
if (percent >= 0 && percent < 100)
text1 = g_strdup_printf (_("%s (downloading)"), ann->name);
else if (percent == -2)
text1 = g_strdup_printf (_("%s (down)"), ann->name);
else
text1 = g_strdup (ann->name);
/* Get length */
length = jmann_get_attr_int (ann, "length");
if (length)
text2 = filesize_to_string(length);
if (ann->url)
ggui_get_pixmaps (ann->url, &pixmap, &mask);
else
{
pixmap = folder_pixmap;
mask = folder_mask;
}
ggui_clist_update_row2 (files_clist, row, text1, text2, pixmap, mask);
g_free (text1);
g_free (text2);
}
void
ggui_file_announce_remove (JMChannel* channel, JMAnn* ann)
{
gint row;
g_return_if_fail (channel && ann);
if (channel == shown_channel && ann == shown_ann)
ggui_file_show (channel, channel->root_ann);
row = gtk_clist_find_row_from_data (files_clist, ann);
if (row >= 0) gtk_clist_remove (files_clist, row);
/* If the file had a File object, it would have been deleted in
ggui_file_remove */
}
/* ************************************************************ */
static GtkFileSelection* add_file_selector;
static GURL* add_file_channel;
static gchar* add_file_path;
static void add_file_ok (GtkButton* button, GtkFileSelection* fs);
static void add_file_cancel (GtkButton* button, GtkFileSelection* fs);
void
ggui_file_add_file (const GURL* channel, const gchar* cpath, const gchar* path)
{
if (!path)
{
if (add_file_selector)
{
gtk_widget_show (GTK_WIDGET(add_file_selector));
return;
}
if (channel && cpath)
{
add_file_channel = gnet_url_clone (channel);
add_file_path = g_strdup (cpath);
}
add_file_selector = GTK_FILE_SELECTION(gtk_file_selection_new(_("Add file to channel")));
GTK_WINDOW(add_file_selector)->position = GTK_WIN_POS_MOUSE;
gtk_signal_connect (GTK_OBJECT (add_file_selector), "destroy",
(GtkSignalFunc) add_file_cancel, NULL);
gtk_signal_connect (GTK_OBJECT (add_file_selector->ok_button), "clicked",
(GtkSignalFunc) add_file_ok, NULL);
gtk_signal_connect (GTK_OBJECT (add_file_selector->cancel_button), "clicked",
(GtkSignalFunc) add_file_cancel, NULL);
gtk_widget_show (GTK_WIDGET(add_file_selector));
return;
}
add_file (channel, cpath, path);
}
static void
add_file_ok (GtkButton* button, GtkFileSelection* fs)
{
gchar* path;
if (!add_file_selector)
return;
path = gtk_file_selection_get_filename (add_file_selector);
if (path && *path)
add_file (add_file_channel, add_file_path, path);
add_file_cancel (NULL, NULL);
}
static void
add_file_cancel (GtkButton* button, GtkFileSelection* fs)
{
if (!add_file_selector)
return;
gtk_widget_destroy(GTK_WIDGET(add_file_selector));
add_file_selector = NULL;
gnet_url_delete (add_file_channel);
add_file_channel = NULL;
g_free (add_file_path);
add_file_path = NULL;
}
static void
add_file (const GURL* channel, const gchar* cpath, const gchar* path)
{
JMAnn* pann;
GURL* url;
gchar* resource;
MtpLocalMirror* mirror;
File* file;
GSHA* sha;
g_return_if_fail (channel);
g_return_if_fail (cpath);
g_return_if_fail (jm_mtp_rvous_url && jm_mtp_server);
/* Check if file exists */
if (!path || !*path || !is_file (path))
{
ggui_show_message ("warning", _("Bad path: %s\n"), path?path:"<null>");
return;
}
/* Check path */
if (!ggui_channel_check_path(channel, cpath, g_basename(path)))
return;
/* Create MTP URL */
url = gnet_url_clone (jm_mtp_rvous_url);
pann = ggui_channel_get_ann (channel, cpath);
if (!strcmp(pann->path, "/"))
resource = g_strconcat ("/", g_basename(path), NULL);
else
resource = g_strconcat (pann->path, "/", g_basename(path), NULL);
gnet_url_set_resource (url, resource);
g_free (resource);
/* Make sure we aren't already mirroring this file */
g_return_if_fail (!g_hash_table_lookup (url_to_file, url));
/* Create MTP client */
mirror = mtp_mirror_path (jm_mtp_server, url, path);
if (!mirror)
{
ggui_show_message ("warning", _("MTP Error - could not add file: %s\n"), path);
gnet_url_delete (url);
return;
}
/* Save file in list */
file = g_new0 (File, 1);
file->mirror = mirror;
file->url = url;
file->path = g_strdup (path);
file->channel = gnet_url_clone (channel);
file->apath = jmann_make_path (pann, g_basename(path));
file->search_id = ggui_search_vfs_add (url, g_basename(path), file_size (path));
file_add (file);
/* Get SHA */
sha = sha_cache_get (sha_cache, path);
/* If we have the SHA, send an announcement now */
if (sha)
{
GGUIP (8, "sha cache hit %s\n", path);
ggui_channel_add_path_sha (channel, file->apath, url, sha);
gnet_sha_delete (sha);
}
/* Otherwise, calculate the SHA asynchronously */
else
file->sha_id = gnet_sha_new_file_async (path, sha_cb, file);
}
static void
sha_cb (GSHA* sha, gpointer user_data)
{
File* file = (File*) user_data;
file->sha_id = NULL;
if (sha)
{
/* Add to cache */
sha_cache_add (sha_cache, file->path, sha);
/* Announce */
ggui_channel_add_path_sha (file->channel, file->apath, file->url, sha);
gnet_sha_delete (sha);
/* TODO: Mirror on SHA? */
}
else
g_warning ("Couldn't calculate SHA for %s\n", file->apath);
}
/* ******************** */
static GtkFileSelection* add_dir_selector;
static GURL* add_dir_channel;
static gchar* add_dir_path;
static void add_dir_ok (GtkButton* button, GtkFileSelection* fs);
static void add_dir_cancel (GtkButton* button, GtkFileSelection* fs);
void
ggui_file_add_dir (const GURL* channel, const gchar* cpath, const gchar* path)
{
if (!path)
{
if (add_dir_selector)
{
gtk_widget_show (GTK_WIDGET(add_dir_selector));
return;
}
if (channel && cpath)
{
add_dir_channel = gnet_url_clone (channel);
add_dir_path = g_strdup (cpath);
}
add_dir_selector = GTK_FILE_SELECTION(gtk_file_selection_new(_("Add directory to channel")));
GTK_WINDOW(add_dir_selector)->position = GTK_WIN_POS_MOUSE;
gtk_signal_connect (GTK_OBJECT (add_dir_selector), "destroy",
(GtkSignalFunc) add_dir_cancel, NULL);
gtk_signal_connect (GTK_OBJECT (add_dir_selector->ok_button), "clicked",
(GtkSignalFunc) add_dir_ok, NULL);
gtk_signal_connect (GTK_OBJECT (add_dir_selector->cancel_button), "clicked",
(GtkSignalFunc) add_dir_cancel, NULL);
gtk_widget_show (GTK_WIDGET(add_dir_selector));
return;
}
add_dir (channel, cpath, path);
}
static void
add_dir_ok (GtkButton* button, GtkFileSelection* fs)
{
gchar* path;
if (!add_dir_selector)
return;
path = gtk_file_selection_get_filename (add_dir_selector);
if (path && *path)
add_dir (add_dir_channel, add_dir_path, path);
add_dir_cancel (NULL, NULL);
}
static void
add_dir_cancel (GtkButton* button, GtkFileSelection* fs)
{
if (!add_dir_selector)
return;
gtk_widget_destroy(GTK_WIDGET(add_dir_selector));
add_dir_selector = NULL;
gnet_url_delete (add_dir_channel);
add_dir_channel = NULL;
g_free (add_dir_path);
add_dir_path = NULL;
}
void
add_dir (const GURL* channel, const gchar* cpath, const gchar* path)
{
g_return_if_fail (channel);
g_return_if_fail (cpath);
/* Add it */
add_file_r (channel, cpath, path);
}
static void
add_file_r (const GURL* channel, const gchar* cpath, const gchar* path)
{
/* If it's a dir, create a dir and add each file in the dir */
if (is_dir (path))
{
gchar* nicepath;
gchar* p;
gchar* basename;
DIR* dir;
gchar* dir_name;
gchar* cpath_new;
struct dirent* de;
nicepath = g_strdup (path);
p = strrchr (nicepath, G_DIR_SEPARATOR);
if (p && p[1] == '\0') /* strip off last separator */
*p = '\0';
basename = g_basename (nicepath);
/* Create directory */
if (create_dir (channel, cpath, basename))
{
g_free (nicepath);
return;
}
/* Open dir */
dir = opendir (path);
if (!dir)
{
g_free (nicepath);
return;
}
/* Create new cpath (must escape name) */
dir_name = stresc (basename, "/\\", '\\');
if (!strcmp (cpath, "/"))
cpath_new = g_strconcat ("/", dir_name, NULL);
else
cpath_new = g_strconcat (cpath, "/", dir_name, NULL);
g_free (dir_name);
while ((de = readdir(dir)) != NULL)
{
gchar* name = de->d_name;
gchar* path_new;
/* Skip . and .. */
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
path_new = g_strconcat (nicepath, G_DIR_SEPARATOR_S, name, NULL);
add_file_r (channel, cpath_new, path_new);
g_free (path_new);
}
g_free (nicepath);
g_free (cpath_new);
/* Close dir */
closedir (dir);
}
/* If it's a file, add the file */
else if (is_file (path))
{
add_file (channel, cpath, path);
}
}
/* ******************** */
static EntryDialog* add_url_dialog;
static GURL* add_url_channel;
static gchar* add_url_path;
static void add_url_ok (gchar* url, gchar* name);
static void add_url_cancel (void);
void
ggui_file_add_url (const GURL* channel, const gchar* path, const gchar* name, const GURL* url)
{
if (!name || !url)
{
if (add_url_dialog)
{
entry_dialog_show (add_url_dialog);
return;
}
if (channel && path)
{
add_url_channel = gnet_url_clone (channel);
add_url_path = g_strdup (path);
}
add_url_dialog = entry_dialog_new(_("Add URL"), _("URL"), _("Name"),
add_url_ok, add_url_cancel);
return;
}
add_url (channel, path, name, url);
}
static void
add_url_ok (gchar* url, gchar* name)
{
GURL* gurl;
gurl = gnet_url_new (url);
if (gurl)
{
add_url (add_url_channel, add_url_path, name, gurl);
gnet_url_delete (gurl);
}
else
ggui_show_message ("warning", _("Malformed URL: %s\n"), url);
add_url_cancel ();
}
static void
add_url_cancel (void)
{
add_url_dialog = NULL;
gnet_url_delete (add_url_channel);
add_url_channel = NULL;
g_free (add_url_path);
add_url_path = NULL;
}
static void
add_url (const GURL* channel, const gchar* path, const gchar* name, const GURL* url)
{
File* file;
JMAnn* ann;
g_return_if_fail (url);
g_return_if_fail (channel);
g_return_if_fail (path);
/* Check if file exists */
if (!path || !*path)
{
ggui_show_message ("warning", _("Bad path: %s\n"), path?path:"<null>");
return;
}
/* Check if path ok */
if (channel && path && !ggui_channel_check_path (channel, path, name))
return;
/* Advertise on channel */
ann = ggui_channel_add (channel, path, name, url);
g_return_if_fail (ann);
/* Create file */
file = g_new0 (File, 1);
file->url = gnet_url_clone (url);
file->channel = gnet_url_clone (channel);
file->apath = g_strdup (ann->path);
file_add (file);
}
/* ******************** */
static EntryDialog* create_dir_dialog;
static GURL* create_dir_channel;
static gchar* create_dir_path;
static void create_dir_ok (gchar* name, gchar* ignore);
static void create_dir_cancel (void);
void
ggui_file_create_dir (const GURL* channel, const gchar* path, const gchar* name)
{
if (!name)
{
if (create_dir_dialog)
{
entry_dialog_show (create_dir_dialog);
return;
}
if (channel && path)
{
create_dir_channel = gnet_url_clone (channel);
create_dir_path = g_strdup (path);
}
create_dir_dialog = entry_dialog_new(_("Create directory"),
_("Directory name"), NULL,
create_dir_ok, create_dir_cancel);
return;
}
create_dir (channel, path, name);
}
static void
create_dir_ok (gchar* name, gchar* ignore)
{
create_dir (create_dir_channel, create_dir_path, name);
create_dir_cancel ();
}
static void
create_dir_cancel (void)
{
create_dir_dialog = NULL;
gnet_url_delete (create_dir_channel);
create_dir_channel = NULL;
g_free (create_dir_path);
create_dir_path = NULL;
}
static gboolean
create_dir (const GURL* channel, const gchar* path, const gchar* name)
{
File* file;
JMAnn* ann;
g_return_val_if_fail (name, TRUE);
/* Check if name ok */
if (!*name)
{
ggui_show_message ("warning", _("Bad directory name: %s\n"), name);
return TRUE;
}
/* Check if path ok */
if (channel && path && !ggui_channel_check_path (channel, path, name))
return TRUE;
/* Advertise on channel */
ann = ggui_channel_add (channel, path, name, NULL);
g_return_val_if_fail (ann, TRUE);
/* Create file */
file = g_new0 (File, 1);
file->channel = gnet_url_clone (channel);
file->apath = g_strdup (ann->path);
file_add (file);
return FALSE;
}
/* ******************** */
void
ggui_file_remove (const GURL* curl, const gchar* apath)
{
JMChannel* channel;
JMAnn* ann;
File* file;
/* Get channel, announcement */
channel = ggui_channel_get (curl);
if (!channel) return;
ann = jmchannel_get (channel, apath);
if (!ann) return;
/* Get file */
file = file_get (curl, apath);
if (!file) return;
/* Remove recursively (it may be a directory with our files in it) */
file_remove_r (curl, ann);
/* Announce remove (this will call ggui_file_announce_remove) */
ggui_channel_remove_path (curl, apath);
}
static void
file_remove_r (const GURL* curl, JMAnn* ann)
{
GList* i;
File* file;
/* Remove children */
for (i = ann->kids; i != NULL; i = i->next)
{
JMAnn* kann;
kann = (JMAnn*) i->data;
file_remove_r (curl, kann);
}
/* Get self */
file = file_get (curl, ann->path);
if (!file) return;
/* Remove */
if (file->url) g_hash_table_remove (url_to_file, file->url);
g_hash_table_remove (name_to_file, file);
file_delete (file);
}
void
ggui_file_leave (const GURL* curl)
{
JMChannel* channel;
/* Remove are sent automatically on a leave. We just remove the
files we had advertised. */
channel = ggui_channel_get (curl);
if (!channel) return;
file_remove_r (curl, channel->root_ann);
}
/* ******************** */
void
ggui_file_update (const GURL* url)
{
GList* i;
g_return_if_fail (url);
if (!shown_channel || !shown_ann)
return;
for (i = shown_ann->kids; i != NULL; i = i->next)
{
JMAnn* ann = (JMAnn*) i->data;
if (ann->url && gnet_url_equal(url, ann->url))
ggui_file_announce_update (shown_channel, ann);
}
/* TODO: Hash from url to anns (may be collisions...) */
}
/* ******************** */
static void
file_add (File* file)
{
g_return_if_fail (file);
g_return_if_fail (file->channel && file->apath);
g_hash_table_insert (name_to_file, file, file);
if (file->url)
g_hash_table_insert (url_to_file, file->url, file);
}
static void
file_delete (File* file)
{
if (!file)
return;
mtp_unmirror (file->mirror);
gnet_url_delete (file->url);
g_free (file->path);
if (file->sha_id)
gnet_sha_new_file_async_cancel (file->sha_id);
if (file->search_id)
ggui_search_vfs_remove (file->search_id);
gnet_url_delete (file->channel);
g_free (file->apath);
g_free (file);
}
static File*
file_get (const GURL* channel, const gchar* path)
{
File key;
key.channel = (GURL*) channel;
key.apath = (gchar*) path;
return (File*) g_hash_table_lookup (name_to_file, &key);
}
static guint
file_hash (gconstpointer p)
{
const File* file = (const File*) p;
guint h;
g_return_val_if_fail (file, 0);
h = g_str_hash(file->apath) ^ gnet_url_hash (file->channel);
return h;
}
static gint
file_equal (gconstpointer p1, gconstpointer p2)
{
const File* file1 = (const File*) p1;
const File* file2 = (const File*) p2;
g_return_val_if_fail (file1, 0);
g_return_val_if_fail (file2, 0);
if (!strcmp (file1->apath, file2->apath) &&
gnet_url_equal (file1->channel, file2->channel))
return 1;
return 0;
}
/* ************************************************************ */
void
on_files_select_row (GtkCList* list, gint row, gint column, GdkEvent* event)
{
gpointer selectee;
selectee = gtk_clist_get_row_data(list, row);
if (selectee != back_pixmap)
{
selected_ann = (JMAnn*) selectee;
ggui_file_update_toolbar ();
}
}
void
on_files_unselect_row (GtkCList* list, gint row, gint column, GdkEvent* event)
{
selected_ann = NULL;
ggui_file_update_toolbar ();
}
/* Return TRUE if we handle event; FALSE to pass on */
gint
on_files_button_press (GtkCList* list, GdkEventButton *event, gpointer user_data)
{
gint row, column;
gboolean rv = FALSE;
/* User double clicked - activate the thing selected */
if (event->type == GDK_2BUTTON_PRESS &&
(event->button == 1 || event->button == 2))
{
/* Get the selection information */
if (gtk_clist_get_selection_info(list, event->x, event->y, &row, &column))
{
/* Select the clicked row, if there is one */
gtk_clist_select_row (list, row, 0);
/* The first row is 'back' */
if (gtk_clist_get_row_data(list, row) == back_pixmap &&
shown_channel && shown_ann && shown_ann->parent)
{
ggui_file_show (shown_channel, shown_ann->parent);
return TRUE;
}
/* Double clicks on files and channels activate them. We
don't do anything for directories because that might be
annoying. */
if (selected_ann && selected_ann->url)
{
/* Use SHA if MTP. on_files_get_file will do this */
if (gnet_url_is_scheme (selected_ann->url, "mtp") &&
!ggui_file_have (selected_ann->url))
on_files_get_file ();
else /* Pass to ggui_activate */
ggui_activate (selected_ann->url);
}
if (selected_ann)
{
/* Double clicks on channels also show them */
if (selected_ann->url && GURL_IS_CHANNEL(selected_ann->url))
{
ggui_channel_select (selected_ann->url);
/* WARNING: this changes selected_ann as a side effect. */
}
else if (!selected_ann->url)
{
ggui_file_show (shown_channel, selected_ann);
}
}
}
else
gtk_clist_unselect_all (list);
rv = TRUE;
}
/* User right-clicked - show context menu */
else if (event->type == GDK_BUTTON_PRESS && event->button == 3)
{
GList* i;
/* Select the clicked row, if there is one */
if (gtk_clist_get_selection_info (list, event->x, event->y, &row, &column))
gtk_clist_select_row (list, row, 0);
else
gtk_clist_unselect_all (list);
/* Hide everything */
for (i = GTK_MENU_SHELL(files_popup)->children; i != NULL; i = i->next)
{
GtkWidget* menu_item = GTK_WIDGET(i->data);
g_assert (GTK_MENU_ITEM(menu_item) != NULL);
gtk_widget_hide (menu_item);
}
/* Update the popup menu */
update_items (NULL);
/* Pop it up */
gtk_menu_popup (GTK_MENU(files_popup), NULL, NULL,
NULL, NULL, 3, event->time);
rv = TRUE;
}
return rv;
}
/* ************************************************************ */
gboolean
on_files_drag_motion (GtkCList* list, GdkDragContext* context,
gint x, gint y, guint time)
{
/* Get the selection information */
if (shown_channel && shown_ann &&
(shown_channel->is_local || !shown_channel->is_channels_only))
{
gdk_drag_status (context, context->suggested_action, time);
}
return TRUE;
}
void
on_files_drag_data_received (GtkCList* list, GdkDragContext* context,
gint x, gint y, GtkSelectionData* sel_data,
guint info, guint time, gpointer user_data)
{
/* Check if the data is valid */
if ((sel_data->length >= 0) && (sel_data->format == 8))
{
if (shown_channel && shown_ann)
{
if (!shown_channel->is_local && shown_channel->is_channels_only)
{
ggui_show_message ("warning", _("This channel allows channels only"));
goto error;
}
switch (info)
{
case DND_TARGET_STRING:
case DND_TARGET_URI_LIST:
{
dnd_parse (sel_data->data, sel_data->length);
gtk_drag_finish (context, TRUE, TRUE, time);
return;
}
}
}
}
error:
gtk_drag_finish (context, FALSE, TRUE, time);
return;
}
static void
dnd_parse (gchar* buf, gint len)
{
gchar* token;
gchar* next = NULL;
g_return_if_fail (shown_channel && shown_ann);
/* Parse each line */
while ((token = strtokq(buf, "\n\r", &next)) != NULL)
{
buf = NULL;
/* Skip the "file:" part, if there is one */
if (strstr(token, "file:") == token)
token = &token[sizeof("file:") - 1];
/* Add it as a file, if it's absolute */
if (token[0] == '/')
{
gchar* path;
gchar* i;
/* Skip /'s */
while (token[1] == '/') token++;
/* Copy and unescape. Mozilla likes to repeat file name at
end. */
path = i = g_malloc(strlen(token)+1);
while (*token)
{
if (token[0] == '%' && token[1] == '2' && token[2] == '0')
{
*i = ' ';
token += 2;
}
else if (token[0] == ' ')
break;
else
*i = *token;
++i;
++token;
}
*i = '\0';
add_file_r (shown_channel->url, shown_ann->path, path);
}
/* Otherwise, try to add as a URL */
else
{
GURL* url;
url = gnet_url_new (token);
if (url)
{
add_url (shown_channel->url, shown_ann->path, token, url);
gnet_url_delete (url);
}
}
}
}
/* ******************** */
void
ggui_file_show_toolbar (void)
{
/* Add everything to the toolbar */
toolbar_append (IT_OPEN_CHANNEL, channel_pixmap, channel_mask,
_("Open channel"), on_files_open_channel);
toolbar_append (IT_CREATE_CHANNEL, create_channel_pixmap, create_channel_mask,
_("Create channel"), on_files_create_channel);
toolbar_append (IT_CREATE_ROOT_CHANNEL, create_priv_channel_pixmap, create_priv_channel_mask,
_("Create private channel"), on_files_create_root_channel);
/* channel from directory */
toolbar_append (IT_JOIN_CHANNEL, join_channel_pixmap, join_channel_mask,
_("Join channel"), on_files_join_channel);
toolbar_append (IT_LEAVE_CHANNEL, leave_channel_pixmap, leave_channel_mask,
_("Leave channel"), on_files_leave_channel);
toolbar_append (IT_ADD_FILE, page_pixmap, page_mask,
_("Add file"), on_files_add_file);
toolbar_append (IT_ADD_DIR, folder_pixmap, folder_mask,
_("Add directory"), on_files_add_directory);
toolbar_append (IT_CREATE_DIR, create_dir_pixmap, create_dir_mask,
_("Create directory"), on_files_create_directory);
toolbar_append (IT_ADD_URL, url_pixmap, url_mask,
_("Add URL"), on_files_add_url);
toolbar_append (IT_CREATE_CHAT, create_chat_pixmap, create_chat_mask,
_("Create chat"), on_files_create_chat);
toolbar_append (IT_JOIN_CHAT, join_chat_pixmap, join_chat_mask,
_("Join chat"), on_files_join_chat);
toolbar_append (IT_LEAVE_CHAT, leave_chat_pixmap, leave_chat_mask,
_("Leave chat"), on_files_leave_chat);
toolbar_append (IT_CREATE_SEARCH, create_search_pixmap, create_search_mask,
_("Create search"), on_files_create_search);
toolbar_append (IT_JOIN_SEARCH, join_search_pixmap, join_search_mask,
_("Join search"), on_files_join_search);
toolbar_append (IT_LEAVE_SEARCH, leave_search_pixmap, gray_search_mask,
_("Leave search"), on_files_leave_search);
toolbar_append (IT_REMOVE, x_pixmap, x_mask,
_("Remove"), on_files_remove);
/* Update the toolbar */
ggui_file_update_toolbar();
}
static void
toolbar_append (Item item, GdkPixmap* gpixmap, GdkBitmap* gbitmap,
const gchar* tooltip, void* func)
{
GtkPixmap* pixmap;
GtkWidget* widget;
pixmap = (GtkPixmap*) gtk_pixmap_new (gpixmap, gbitmap);
g_return_if_fail (pixmap);
widget = gtk_toolbar_append_item (jmw_toolbar, NULL,
tooltip, "private",
GTK_WIDGET(pixmap),
(GtkSignalFunc) func, NULL);
g_return_if_fail (widget);
gtk_object_set_user_data (GTK_OBJECT(widget), (gpointer) item);
}
void
ggui_file_update_toolbar (void)
{
GList* kids;
GList* i;
/* Hide all */
kids = gtk_container_children (GTK_CONTAINER(jmw_toolbar));
for (i = kids; i != NULL; i = i->next)
gtk_widget_set_sensitive (GTK_WIDGET(i->data), FALSE);
/* Update toolbar */
update_items (kids);
g_list_free (kids);
}
/* ************************************************************ */
static const char* item_mi_name[] =
{
"create_root_channel_mi", /* 0 */
"create_channel_mi",
"create_channel_from_directory_mi",
"open_channel_mi",
"join_channel_mi",
"leave_channel_mi", /* 5 */
"leave_current_channel_mi",
"remove_channel_mi",
"remove_current_channel_mi",
"add_file_mi",
"get_file_mi", /* 10 */
"cancel_download_mi",
"remove_file_mi",
"create_directory_mi",
"add_directory_mi",
"get_directory_mi", /* 15 */
"remove_directory_mi",
"add_url_mi",
"open_url_mi",
"remove_url_mi",
"create_chat_mi", /* 20 */
"join_chat_mi",
"leave_chat_mi",
"remove_chat_mi",
"create_search_mi",
"join_search_mi", /* 25 */
"leave_search_mi",
"remove_search_mi",
"remove_mi",
"properties_mi",
"separator1",
"separator2", /* 30 */
"separator3",
"exit_mi",
};
static void
update_items (void* widget)
{
GURL* sc_url;
show_item (widget, IT_OPEN_CHANNEL);
show_item (widget, IT_CREATE_ROOT_CHANNEL);
/* If there is a selected channel, show join and leave */
if ((sc_url = ggui_channel_get_selected()) != NULL)
{
JMChannel* sc = ggui_channel_get (sc_url);
if (sc->is_local)
/* REMOVE */;
else if (jmchannel_is_up(sc))
show_item (widget, IT_LEAVE_CHANNEL);
else
show_item (widget, IT_JOIN_CHANNEL);
}
if (shown_channel)
{
if (jmchannel_is_up (shown_channel))
{
if (!shown_channel->is_channels_only)
{
show_item (widget, IT_ADD_FILE);
show_item (widget, IT_ADD_URL);
show_item (widget, IT_ADD_DIR);
show_item (widget, IT_CREATE_CHAT);
show_item (widget, IT_CREATE_SEARCH);
show_item (widget, IT_CREATE_DIR);
}
show_item (widget, IT_CREATE_CHANNEL);
/* show_item (widget, IT_CREATE_CHANNEL_FROM_DIR); */
show_item (widget, IT_SEPARATOR2);
if (shown_channel->is_local)
show_item (widget, IT_REMOVE_CURRENT_CHANNEL);
else if (jmchannel_is_up (shown_channel))
show_item (widget, IT_LEAVE_CURRENT_CHANNEL);
}
}
if (selected_ann)
{
GURL* url = selected_ann->url;
show_item (widget, IT_SEPARATOR3);
if (url)
show_item (widget, IT_PROPERTIES);
g_return_if_fail (shown_channel && shown_ann);
if (!url)
{
show_item (widget, IT_SEPARATOR1);
if (selected_ann->is_local)
{
show_item (widget, IT_REMOVE_DIR);
show_item (widget, IT_REMOVE);
}
/* else */
/* show_item (widget, IT_GET_DIR); */
}
else if (GURL_IS_FILE (url))
{
gint percent;
show_item (widget, IT_SEPARATOR1);
percent = ggui_download_get_percent_complete (url);
if (selected_ann->is_local)
{
show_item (widget, IT_REMOVE_FILE);
show_item (widget, IT_REMOVE);
}
else if (percent >= 0 && percent <= 99)
show_item (widget, IT_CANCEL_DOWNLOAD);
else if (percent == -2 || percent == 0)
show_item (widget, IT_GET_FILE);
}
else if (GURL_IS_CHANNEL (url))
{
show_item (widget, IT_SEPARATOR1);
if (selected_ann->is_local)
{
show_item (widget, IT_REMOVE_CHANNEL);
show_item (widget, IT_REMOVE);
}
else if (ggui_channel_is_up (url))
show_item (widget, IT_LEAVE_CHANNEL);
else
show_item (widget, IT_JOIN_CHANNEL);
}
else if (GURL_IS_CHAT (url))
{
show_item (widget, IT_SEPARATOR1);
if (selected_ann->is_local)
{
show_item (widget, IT_REMOVE_CHAT);
show_item (widget, IT_REMOVE);
}
else if (ggui_chat_is_up (url))
show_item (widget, IT_LEAVE_CHAT);
else
show_item (widget, IT_JOIN_CHAT);
}
else if (GURL_IS_SEARCH (url))
{
show_item (widget, IT_SEPARATOR1);
if (selected_ann->is_local)
{
show_item (widget, IT_REMOVE_SEARCH);
show_item (widget, IT_REMOVE);
}
else if (ggui_search_is_up (url))
show_item (widget, IT_LEAVE_SEARCH);
else
show_item (widget, IT_JOIN_SEARCH);
}
else
{
if (selected_ann->is_local)
{
show_item (widget, IT_REMOVE_URL);
show_item (widget, IT_REMOVE);
}
show_item (widget, IT_OPEN_URL);
}
}
else
{
show_item (widget, IT_SEPARATOR3);
show_item (widget, IT_EXIT);
}
}
static void
show_item (void* widget, Item it)
{
if (!widget) /* Popup menu */
{
GtkWidget* menu_item = glade_xml_get_widget(menu_xml, item_mi_name[it]);
if (menu_item)
gtk_widget_show(menu_item);
}
else /* Toolbar */
{
GList* kids = (GList*) widget;
GList* i;
for (i = kids; i != NULL; i = i->next)
{
if (it == (guint) gtk_object_get_user_data(GTK_OBJECT(i->data)))
{
gtk_widget_set_sensitive (GTK_WIDGET(i->data), TRUE);
break;
}
}
}
}
POPUPFUNC (on_files_get_file)
{
GSHA* sha;
gchar* path = NULL;
/* FIX: Download directory recursively */
g_return_if_fail (shown_channel && selected_ann && selected_ann->url);
/* TODO: Handle other directory separators */
if (G_DIR_SEPARATOR == '/')
path = g_strconcat (jmchannel_get_name(shown_channel),
selected_ann->parent->path, NULL);
sha = jmann_get_attr_sha (selected_ann, "sha");
ggui_download_get (selected_ann->url, path, sha);
g_free (path);
gnet_sha_delete (sha);
}
POPUPFUNC (on_files_cancel_download)
{
g_return_if_fail (selected_ann && selected_ann->url);
ggui_download_cancel (selected_ann->url);
}
POPUPFUNC (on_files_remove_file)
{
g_return_if_fail (shown_channel && selected_ann);
ggui_file_remove (shown_channel->url, selected_ann->path);
}
POPUPFUNC (on_files_open_url)
{
g_return_if_fail (selected_ann && selected_ann->url);
ggui_activate (selected_ann->url);
}
POPUPFUNC (on_files_remove_url)
{
g_return_if_fail (shown_channel && selected_ann);
ggui_file_remove (shown_channel->url, selected_ann->path);
}
POPUPFUNC (on_files_join_channel)
{
GURL* sc_url;
if (selected_ann && selected_ann->url &&
gnet_url_is_scheme (selected_ann->url, "jm"))
ggui_channel_join (selected_ann->url);
else if ((sc_url = ggui_channel_get_selected()) != NULL)
ggui_channel_join (sc_url);
}
POPUPFUNC (on_files_remove_channel)
{
g_return_if_fail (selected_ann && selected_ann->url);
ggui_channel_delete (selected_ann->url);
}
POPUPFUNC (on_files_leave_channel)
{
GURL* sc_url;
if (selected_ann && selected_ann->url &&
gnet_url_is_scheme (selected_ann->url, "jm"))
ggui_channel_leave (selected_ann->url);
else if ((sc_url = ggui_channel_get_selected()) != NULL)
ggui_channel_leave (sc_url);
}
POPUPFUNC (on_files_join_chat)
{
g_return_if_fail (selected_ann && selected_ann->url);
ggui_chat_join (selected_ann->url);
}
POPUPFUNC (on_files_remove_chat)
{
g_return_if_fail (selected_ann && selected_ann->url);
ggui_chat_remove (selected_ann->url);
}
POPUPFUNC (on_files_leave_chat)
{
g_return_if_fail (selected_ann && selected_ann->url);
ggui_chat_leave (selected_ann->url);
}
POPUPFUNC (on_files_join_search)
{
g_return_if_fail (selected_ann && selected_ann->url);
ggui_search_join (selected_ann->url);
}
POPUPFUNC (on_files_remove_search)
{
g_return_if_fail (selected_ann && selected_ann->url);
ggui_search_remove (selected_ann->url);
}
POPUPFUNC (on_files_leave_search)
{
g_return_if_fail (selected_ann && selected_ann->url);
ggui_search_leave (selected_ann->url);
}
/* ********** */
POPUPFUNC (on_files_add_file)
{
g_return_if_fail (shown_channel && shown_ann);
ggui_file_add_file (shown_channel->url, shown_ann->path, NULL);
}
POPUPFUNC (on_files_add_directory)
{
g_return_if_fail (shown_channel && shown_ann);
ggui_file_add_dir (shown_channel->url, shown_ann->path, NULL);
}
POPUPFUNC (on_files_add_url)
{
g_return_if_fail (shown_channel && shown_ann);
ggui_file_add_url (shown_channel->url, shown_ann->path, NULL, NULL);
}
POPUPFUNC (on_files_create_chat)
{
g_return_if_fail (shown_channel && shown_ann);
ggui_chat_create (shown_channel->url, shown_ann->path, NULL);
}
POPUPFUNC (on_files_create_search)
{
g_return_if_fail (shown_channel && shown_ann);
ggui_search_create (shown_channel->url, shown_ann->path, NULL);
}
POPUPFUNC (on_files_create_directory)
{
g_return_if_fail (shown_channel && shown_ann);
ggui_file_create_dir (shown_channel->url, shown_ann->path, NULL);
}
POPUPFUNC (on_files_create_channel)
{
g_return_if_fail (shown_channel && shown_ann);
ggui_channel_create (shown_channel->url, shown_ann->path, NULL);
}
POPUPFUNC (on_files_create_channel_from_directory)
{
g_print ("FIX IMPLEMENT\n");
/* ggui_menu_create_channel_from_directory (&shown_file); FIX */
}
POPUPFUNC (on_files_open_channel)
{
ggui_channel_join (NULL);
}
POPUPFUNC (on_files_create_root_channel)
{
ggui_channel_create (NULL, NULL, NULL);
}
POPUPFUNC (on_files_remove_current_channel)
{
g_return_if_fail (shown_channel);
ggui_channel_delete (shown_channel->url);
}
POPUPFUNC (on_files_leave_current_channel)
{
g_return_if_fail (shown_channel);
ggui_channel_leave (shown_channel->url);
}
POPUPFUNC (on_files_remove)
{
GURL* url;
g_return_if_fail (selected_ann);
url = selected_ann->url;
if (!url)
ggui_file_remove (shown_channel->url, selected_ann->path);
else if (gnet_url_is_scheme (url, "jm"))
ggui_channel_delete (url);
else if (gnet_url_is_scheme (url, "mtp"))
{
if (selected_ann->is_local)
ggui_file_remove (shown_channel->url, selected_ann->path);
else
ggui_download_cancel (url);
}
else if (gnet_url_is_scheme (url, "jmchat"))
ggui_chat_remove (url);
else if (gnet_url_is_scheme (url, "jmmsp"))
ggui_search_remove (url);
else if (selected_ann->is_local)
ggui_file_remove (shown_channel->url, selected_ann->path);
}
POPUPFUNC (on_files_properties)
{
g_return_if_fail (selected_ann && selected_ann->url);
ggui_properties_show (selected_ann->url);
/* TODO directory properties */
}
syntax highlighted by Code2HTML, v. 0.9.1