1 /*
2  * Copyright © 2004-2010 Jens Oknelid, paskharen@gmail.com
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * In addition, as a special exception, compiling, linking, and/or
19  * using OpenSSL with this program is allowed.
20  */
21 
22 #include "sharebrowser.hh"
23 #include <iostream>
24 #include <dcpp/FavoriteManager.h>
25 #include <dcpp/ShareManager.h>
26 #include <dcpp/Text.h>
27 #include <dcpp/ADLSearch.h>
28 #include "search.hh"
29 #include "settingsmanager.hh"
30 #include "UserCommandMenu.hh"
31 #include "wulformanager.hh"
32 #include "WulforUtil.hh"
33 
34 using namespace std;
35 using namespace dcpp;
36 
ShareBrowser(UserPtr user,const string & file,const string & initialDirectory,bool full)37 ShareBrowser::ShareBrowser(UserPtr user, const string &file, const string &initialDirectory, bool full):
38     BookEntry(Entry::SHARE_BROWSER, _("List: ") + WulforUtil::getNicks(user, ""), "sharebrowser.ui", user->getCID().toBase32()),
39     user(user),
40     file(file),
41     initialDirectory(initialDirectory),
42     listing(HintedUser(user, "")),
43     shareSize(0),
44     currentSize(0),
45     shareItems(0),
46     currentItems(0),
47     updateFileView(TRUE),
48     skipHits(0),
49     full(full)
50 {
51 #if !GTK_CHECK_VERSION(3,0,0)
52     gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR(getWidget("mainStatus")),FALSE);
53     gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR(getWidget("itemsStatus")),FALSE);
54     gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR(getWidget("sizeStatus")),FALSE);
55     gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR(getWidget("filesStatus")),FALSE);
56     gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR(getWidget("totalStatus")),FALSE);
57 #endif
58 
59     // Use the nick from the file name in case the user is offline and core only returns CID
60     nick = WulforUtil::getNicks(user, "");
61     if (nick.find(user->getCID().toBase32(), 1) != string::npos)
62     {
63         string name = Util::getFileName(file);
64         string::size_type loc = name.find('.');
65         nick = name.substr(0, loc);
66         setLabel_gui(_("List: ") + nick);
67     }
68 
69     // Configure the dialogs
70     File::ensureDirectory(SETTING(DOWNLOAD_DIRECTORY));
71     gtk_dialog_set_alternative_button_order(GTK_DIALOG(getWidget("findDialog")), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1);
72     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(getWidget("dirChooserDialog")), Text::fromUtf8(SETTING(DOWNLOAD_DIRECTORY)).c_str());
73     gtk_dialog_set_alternative_button_order(GTK_DIALOG(getWidget("dirChooserDialog")), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1);
74 
75     // menu
76     g_object_ref_sink(getWidget("dirMenu"));
77     g_object_ref_sink(getWidget("fileMenu"));
78 
79     // Set the pane position
80     gtk_paned_set_position(GTK_PANED(getWidget("pane")), WGETI("sharebrowser-pane-position"));
81 
82     // Initialize the file TreeView
83     fileView.setView(GTK_TREE_VIEW(getWidget("fileView")), true, "sharebrowser");
84     fileView.insertColumn(_("Filename"), G_TYPE_STRING, TreeView::ICON_STRING, 400, "Icon");
85     fileView.insertColumn(_("Size"), G_TYPE_STRING, TreeView::STRINGR, 80);
86     fileView.insertColumn(_("Type"), G_TYPE_STRING, TreeView::STRING, 50);
87     fileView.insertColumn(_("TTH"), G_TYPE_STRING, TreeView::STRING, 150);
88     fileView.insertColumn(_("Exact Size"), G_TYPE_STRING, TreeView::STRINGR, 105);
89     fileView.insertColumn(_("Bitrate"), G_TYPE_STRING, TreeView::STRING, 50);
90     fileView.insertColumn(_("Resolution"), G_TYPE_STRING, TreeView::STRING, 70);
91     fileView.insertColumn(_("Video"), G_TYPE_STRING, TreeView::STRING, 100);
92     fileView.insertColumn(_("Audio"), G_TYPE_STRING, TreeView::STRING, 70);
93     fileView.insertColumn(_("Downloaded"), G_TYPE_STRING, TreeView::STRING, 70);
94     fileView.insertColumn(_("Shared"), G_TYPE_STRING, TreeView::STRING, 70);
95     fileView.insertHiddenColumn("DL File", G_TYPE_POINTER);
96     fileView.insertHiddenColumn("Icon", G_TYPE_STRING);
97     fileView.insertHiddenColumn("Size Order", G_TYPE_INT64);
98     fileView.insertHiddenColumn("File Order", G_TYPE_STRING);
99     fileView.insertHiddenColumn("Shared Order", G_TYPE_INT64);
100     fileView.finalize();
101     fileStore = gtk_list_store_newv(fileView.getColCount(), fileView.getGTypes());
102     gtk_tree_view_set_model(fileView.get(), GTK_TREE_MODEL(fileStore));
103     g_object_unref(fileStore);
104     fileSelection = gtk_tree_view_get_selection(fileView.get());
105     gtk_tree_selection_set_mode(gtk_tree_view_get_selection(fileView.get()), GTK_SELECTION_MULTIPLE);
106     gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(fileStore), fileView.col("File Order"), GTK_SORT_ASCENDING);
107     gtk_tree_view_column_set_sort_indicator(gtk_tree_view_get_column(fileView.get(), fileView.col(_("Filename"))), TRUE);
108     gtk_tree_view_set_fixed_height_mode(fileView.get(), TRUE);
109     fileView.setSortColumn_gui(_("Filename"), "File Order");
110     fileView.setSortColumn_gui(_("Size"), "Size Order");
111     fileView.setSortColumn_gui(_("Exact Size"), "Size Order");
112     fileView.setSortColumn_gui(_("Shared"), "Shared Order");
113 
114     // Initialize the directory treeview
115     dirView.setView(GTK_TREE_VIEW(getWidget("dirView")));
116     dirView.insertColumn(_("Dir"), G_TYPE_STRING, TreeView::ICON_STRING, -1, "Icon");
117     dirView.insertHiddenColumn("DL Dir", G_TYPE_POINTER);
118     dirView.insertHiddenColumn("Icon", G_TYPE_STRING);
119     dirView.finalize();
120     dirStore = gtk_tree_store_newv(dirView.getColCount(), dirView.getGTypes());
121     gtk_tree_view_set_model(dirView.get(), GTK_TREE_MODEL(dirStore));
122     g_object_unref(dirStore);
123     dirSelection = gtk_tree_view_get_selection(dirView.get());
124     gtk_tree_view_set_enable_tree_lines(dirView.get(), TRUE);
125 
126     // Initialize the user command menus
127     fileUserCommandMenu = new UserCommandMenu(getWidget("fileUserCommandMenu"), ::UserCommand::CONTEXT_FILELIST);
128     addChild(fileUserCommandMenu);
129     dirUserCommandMenu = new UserCommandMenu(getWidget("dirUserCommandMenu"), ::UserCommand::CONTEXT_FILELIST);
130     addChild(dirUserCommandMenu);
131 
132     // Connect the signals to their callback functions.
133     g_signal_connect(fileView.get(), "button-press-event", G_CALLBACK(onButtonPressed_gui), (gpointer)this);
134     g_signal_connect(fileView.get(), "button-release-event", G_CALLBACK(onFileButtonReleased_gui), (gpointer)this);
135     g_signal_connect(fileView.get(), "key-release-event", G_CALLBACK(onFileKeyReleased_gui), (gpointer)this);
136     g_signal_connect(dirView.get(), "button-press-event", G_CALLBACK(onButtonPressed_gui), (gpointer)this);
137     g_signal_connect(dirView.get(), "button-release-event", G_CALLBACK(onDirButtonReleased_gui), (gpointer)this);
138     g_signal_connect(dirView.get(), "key-release-event", G_CALLBACK(onDirKeyReleased_gui), (gpointer)this);
139     g_signal_connect(getWidget("matchButton"), "clicked", G_CALLBACK(onMatchButtonClicked_gui), (gpointer)this);
140     g_signal_connect(getWidget("findButton"), "clicked", G_CALLBACK(onFindButtonClicked_gui), (gpointer)this);
141     g_signal_connect(getWidget("nextButton"), "clicked", G_CALLBACK(onNextButtonClicked_gui), (gpointer)this);
142     g_signal_connect(getWidget("dirDownloadItem"), "activate", G_CALLBACK(onDownloadDirClicked_gui), (gpointer)this);
143     g_signal_connect(getWidget("fileDownloadItem"), "activate", G_CALLBACK(onDownloadClicked_gui), (gpointer)this);
144     g_signal_connect(getWidget("searchForAlternatesItem"), "activate", G_CALLBACK(onSearchAlternatesClicked_gui), (gpointer)this);
145     g_signal_connect(getWidget("copyMagnetItem"), "activate", G_CALLBACK(onCopyMagnetClicked_gui), (gpointer)this);
146     g_signal_connect(getWidget("copyPictureItem"), "activate", G_CALLBACK(onCopyPictureClicked_gui), (gpointer)this);
147 
148 #if !GLIB_CHECK_VERSION(2,32,0)
149     GError *error = NULL;
150     g_thread_create(threadLoad_list, (gpointer)this, FALSE, &error);
151     if (error)
152     {
153         cerr << "Unable to create filelist loader thread: " << error->message << endl;
154         g_error_free(error);
155     }
156 #else
157     g_thread_new("filelistloader",threadLoad_list, (gpointer)this);
158 #endif
159 }
160 
~ShareBrowser()161 ShareBrowser::~ShareBrowser()
162 {
163     // Save the pane position
164     int panePosition = gtk_paned_get_position(GTK_PANED(getWidget("pane")));
165     WSET("sharebrowser-pane-position", panePosition);
166 
167     gtk_widget_destroy(getWidget("findDialog"));
168     gtk_widget_destroy(getWidget("dirChooserDialog"));
169 
170     g_object_unref(getWidget("dirMenu"));
171     g_object_unref(getWidget("fileMenu"));
172 }
isFull()173 bool ShareBrowser::isFull()
174 {
175     return full;
176 }
177 
show()178 void ShareBrowser::show()
179 {
180     updateStatus_gui();
181     WulforManager::get()->getMainWindow()->setMainStatus_gui(_("File list loaded"));
182 }
183 
threadLoad_list(gpointer data)184 gpointer ShareBrowser::threadLoad_list(gpointer data)
185 {
186     ShareBrowser *man = (ShareBrowser *)data;
187     man->setStatus_gui("mainStatus", _("Parse and build tree..."));
188     if (man->buildList_gui())
189         man->setStatus_gui("mainStatus", _("Done"));
190     return NULL;
191 }
192 
buildList_gui()193 bool ShareBrowser::buildList_gui()
194 {
195     // Load the xml file containing the share list.
196     try
197     {
198         // Set name of root entry to user nick.
199         listing.getRoot()->setName(nick);
200 
201         if (full) {
202             listing.loadFile(file);
203 
204             // Search ADL
205             ADLSearchManager::getInstance()->matchListing(listing);
206         }
207         // Add entries to dir tree view starting with the root entry.
208         buildDirs_gui(listing.getRoot(), NULL);
209 
210         if (full) {
211             openDir_gui(initialDirectory);
212         }
213     }
214     catch (const Exception &e)
215     {
216         setStatus_gui("mainStatus", _("Unable to load file list: ") + e.getError());
217         return FALSE;
218     }
219     return TRUE;
220 }
221 
222 /*
223  * Selects the directory in the tree view, and shows that directory's contents.
224  */
openDir_gui(const string & dir)225 void ShareBrowser::openDir_gui(const string &dir)
226 {
227     GtkTreeIter iter;
228 
229     if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dirStore), &iter))
230     {
231         GtkTreePath *path;
232         DirectoryListing::Directory *directory;
233 
234         if (findDir_gui(dir, &iter))
235             path = gtk_tree_model_get_path(GTK_TREE_MODEL(dirStore), &iter);
236         else
237             path = gtk_tree_path_new_first();
238 
239         directory = dirView.getValue<gpointer, DirectoryListing::Directory *>(&iter, "DL Dir");
240 
241         gtk_tree_view_expand_to_path(dirView.get(), path);
242         gtk_tree_view_scroll_to_cell(dirView.get(), path, gtk_tree_view_get_column(dirView.get(), 0), FALSE, 0.0, 0.0);
243         gtk_tree_view_set_cursor(dirView.get(), path, NULL, FALSE);
244         gtk_tree_path_free(path);
245 
246         updateFiles_gui(directory);
247     }
248 }
249 
findDir_gui(const string & dir,GtkTreeIter * parent)250 bool ShareBrowser::findDir_gui(const string &dir, GtkTreeIter *parent)
251 {
252     if (dir.empty())
253         return TRUE;
254 
255     string::size_type i = dir.find_first_of(PATH_SEPARATOR);
256     const string &current = dir.substr(0, i);
257     GtkTreeIter iter;
258     bool valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(dirStore), &iter, parent);
259 
260     while (valid)
261     {
262         if (dirView.getString(&iter, _("Dir")) == current)
263         {
264             *parent = iter;
265             return findDir_gui(dir.substr(i + 1), parent);
266         }
267 
268         valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(dirStore), &iter);
269     }
270 
271     return FALSE;
272 }
273 
buildDirs_gui(DirectoryListing::Directory * dir,GtkTreeIter * iter)274 void ShareBrowser::buildDirs_gui(DirectoryListing::Directory *dir, GtkTreeIter *iter)
275 {
276     DirectoryListing::Directory::Iter it;
277     DirectoryListing::File::Iter file;
278     GtkTreeIter newIter;
279 
280     gtk_tree_store_append(dirStore, &newIter, iter);
281     gtk_tree_store_set(dirStore, &newIter, dirView.col(_("Dir")), dir->getName().c_str(), -1);
282 
283     gtk_tree_store_set(dirStore, &newIter,
284         dirView.col("DL Dir"), (gpointer)dir,
285         dirView.col("Icon"), "icon-directory",
286         -1);
287 
288     for (file = dir->files.begin(); file != dir->files.end(); ++file)
289     {
290         shareItems++;
291         shareSize += (*file)->getSize();
292     }
293 
294     // Recursive call for all subdirs of current dir.
295     std::sort(dir->directories.begin(), dir->directories.end(), DirectoryListing::Directory::DirSort());
296     for (it = dir->directories.begin(); it != dir->directories.end(); ++it)
297         buildDirs_gui(*it, &newIter);
298 }
299 
updateFiles_gui(DirectoryListing::Directory * dir)300 void ShareBrowser::updateFiles_gui(DirectoryListing::Directory *dir)
301 {
302     DirectoryListing::Directory::List *dirs = &(dir->directories);
303     DirectoryListing::Directory::Iter it_dir;
304     DirectoryListing::File::List *files = &(dir->files);
305     DirectoryListing::File::Iter it_file;
306     GtkTreeIter iter;
307     int64_t size;
308     gint sortColumn;
309     GtkSortType sortType;
310 
311     currentSize = 0;
312     currentItems = 0;
313 
314     gtk_list_store_clear(fileStore);
315 
316     gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(fileStore), &sortColumn, &sortType);
317     gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(fileStore), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, sortType);
318 
319     // Add directories to the store.
320     for (it_dir = dirs->begin(); it_dir != dirs->end(); ++it_dir)
321     {
322         gtk_list_store_append(fileStore, &iter);
323         gtk_list_store_set(fileStore, &iter,
324             fileView.col(_("Filename")), Util::getFileName((*it_dir)->getName()).c_str(),
325             fileView.col("File Order"), Util::getFileName("d"+(*it_dir)->getName()).c_str(),
326             -1);
327 
328         size = (*it_dir)->getTotalSize(false);
329         gtk_list_store_set(fileStore, &iter,
330             fileView.col("Icon"), "icon-directory",
331             fileView.col(_("Size")), Util::formatBytes(size).c_str(),
332             fileView.col(_("Exact Size")), Util::formatExactSize(size).c_str(),
333             fileView.col("Size Order"), size,
334             fileView.col(_("Type")), _("Directory"),
335             fileView.col("DL File"), (gpointer)(*it_dir),
336             fileView.col(_("TTH")), "",
337             -1);
338 
339         currentSize += size;
340         currentItems++;
341     }
342 
343     // Add files to the store.
344     for (it_file = files->begin(); it_file != files->end(); ++it_file)
345     {
346         gtk_list_store_append(fileStore, &iter);
347 
348         // If ext is empty we cannot do substr on it.
349         string ext = Util::getFileExt((*it_file)->getName());
350         if(!ext.empty())
351             ext = ext.substr(1);
352 
353         gtk_list_store_set(fileStore, &iter,
354             fileView.col(_("Filename")), Util::getFileName((*it_file)->getName()).c_str(),
355             fileView.col(_("Type")), ext.c_str(),
356             fileView.col("File Order"), Util::getFileName("f"+(*it_file)->getName()).c_str(),
357             -1);
358 
359         size = (*it_file)->getSize();
360         gtk_list_store_set(fileStore, &iter,
361             fileView.col("Icon"), "icon-file",
362             fileView.col(_("Size")), Util::formatBytes(size).c_str(),
363             fileView.col(_("Exact Size")), Util::formatExactSize(size).c_str(),
364             fileView.col("Size Order"), size,
365             fileView.col("DL File"), (gpointer)(*it_file),
366             fileView.col(_("TTH")), (*it_file)->getTTH().toBase32().c_str(),
367             fileView.col(_("Bitrate")), ((*it_file)->mediaInfo.bitrate) ? (Util::toString((*it_file)->mediaInfo.bitrate)).c_str() : Util::emptyString.c_str(),
368             fileView.col(_("Resolution")), !(*it_file)->mediaInfo.video_info.empty() ? (*it_file)->mediaInfo.resolution.c_str() : Util::emptyString.c_str(),
369             fileView.col(_("Video")), (*it_file)->mediaInfo.video_info.c_str(),
370             fileView.col(_("Audio")), (*it_file)->mediaInfo.audio_info.c_str(),
371             fileView.col(_("Downloaded")), (Util::toString((*it_file)->getHit())).c_str(),
372             fileView.col(_("Shared")), (Util::formatTime("%Y-%m-%d %H:%M", (*it_file)->getTS())).c_str(),
373             fileView.col("Shared Order"), (*it_file)->getTS(),
374             -1);
375 
376         currentSize += size;
377         currentItems++;
378     }
379 
380     gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(fileStore), sortColumn, sortType);
381     //gtk_tree_view_scroll_to_point(fileView.get(), 0, 0);
382     updateStatus_gui();
383     updateFileView = TRUE;
384 }
385 
updateStatus_gui()386 void ShareBrowser::updateStatus_gui()
387 {
388     string items, files, size, total;
389     files = _("Files: ") + Util::toString(shareItems);
390     total = _("Total: ") + Util::formatBytes(shareSize);
391 
392     if (gtk_tree_selection_get_selected(dirSelection, NULL, NULL))
393     {
394         items = _("Items: ") + Util::toString(currentItems);
395         size = _("Size: ") + Util::formatBytes(currentSize);
396     }
397     else
398     {
399         items = _("Items: 0");
400         size = _("Size: 0 B");
401     }
402 
403     setStatus_gui("itemsStatus", items);
404     setStatus_gui("sizeStatus", size);
405     setStatus_gui("filesStatus", files);
406     setStatus_gui("totalStatus", total);
407 }
408 
setStatus_gui(string statusBar,string msg)409 void ShareBrowser::setStatus_gui(string statusBar, string msg)
410 {
411     gtk_statusbar_pop(GTK_STATUSBAR(getWidget(statusBar)), 0);
412     gtk_statusbar_push(GTK_STATUSBAR(getWidget(statusBar)), 0, msg.c_str());
413 }
414 
fileViewSelected_gui()415 void ShareBrowser::fileViewSelected_gui()
416 {
417     gpointer ptr;
418     string fileOrder;
419     GtkTreeIter iter, parentIter;
420     GtkTreeModel *m = GTK_TREE_MODEL(fileStore);
421     GList *list = gtk_tree_selection_get_selected_rows(fileSelection, NULL);
422     GtkTreePath *path = (GtkTreePath *)g_list_nth_data(list, 0);
423 
424     if (gtk_tree_model_get_iter(m, &iter, path))
425     {
426         ptr = fileView.getValue<gpointer>(&iter, "DL File");
427         fileOrder = fileView.getString(&iter, "File Order");
428         int64_t filesize = fileView.getValue<int64_t>(&iter, "Size Order");
429 
430         if (fileOrder[0] == 'd' && gtk_tree_selection_get_selected(dirSelection, NULL, &parentIter))
431         {
432             m = GTK_TREE_MODEL(dirStore);
433             gboolean valid = gtk_tree_model_iter_children(m, &iter, &parentIter);
434 
435             while (valid && ptr != dirView.getValue<gpointer>(&iter, "DL Dir"))
436                 valid = gtk_tree_model_iter_next(m, &iter);
437 
438             if (!full && !filesize) {
439                 typedef Func1<ShareBrowser, DirectoryListing::Directory*> F1;
440                 F1 *func = new F1(this,&ShareBrowser::downloadChangedDir,
441                 (DirectoryListing::Directory *)dirView.getValue<gpointer>(&iter, "DL Dir"));
442                 WulforManager::get()->dispatchClientFunc(func);
443                 path = gtk_tree_model_get_path(m, &iter);
444                 gtk_tree_view_expand_to_path(dirView.get(), path);
445                 gtk_tree_view_set_cursor(dirView.get(), path, NULL, FALSE);
446             } else {
447                 updateFiles_gui((DirectoryListing::Directory *)ptr);
448             }
449         }
450         else
451             downloadSelectedFiles_gui(Text::fromUtf8(SETTING(DOWNLOAD_DIRECTORY)));
452     }
453 
454     gtk_tree_path_free(path);
455     g_list_free(list);
456 }
457 
downloadSelectedFiles_gui(const string & target)458 void ShareBrowser::downloadSelectedFiles_gui(const string &target)
459 {
460     gpointer ptr;
461     string fileOrder;
462     string filename;
463     GtkTreeIter iter;
464     GtkTreePath *path;
465     DirectoryListing::File *file;
466     DirectoryListing::Directory *dir;
467     GList *list = gtk_tree_selection_get_selected_rows(fileSelection, NULL);
468 
469     for (GList *i = list; i; i = i->next)
470     {
471         path = (GtkTreePath *)i->data;
472         if (gtk_tree_model_get_iter(GTK_TREE_MODEL(fileStore), &iter, path))
473         {
474             ptr = fileView.getValue<gpointer>(&iter, "DL File");
475             fileOrder = fileView.getString(&iter, "File Order");
476 
477             if (fileOrder[0] == 'd')
478             {
479                 dir = (DirectoryListing::Directory *)ptr;
480 
481                 typedef Func2<ShareBrowser, DirectoryListing::Directory *, string> F2;
482                 F2 * func = new F2(this, &ShareBrowser::downloadDir_client, dir, target);
483                 WulforManager::get()->dispatchClientFunc(func);
484             }
485             else
486             {
487                 file = (DirectoryListing::File *)ptr;
488 
489                 string filename = Util::getFileName(file->getName());
490 
491                 typedef Func2<ShareBrowser, DirectoryListing::File *, string> F2;
492                 F2 * func = new F2(this, &ShareBrowser::downloadFile_client, file, target + filename);
493                 WulforManager::get()->dispatchClientFunc(func);
494             }
495         }
496         gtk_tree_path_free(path);
497     }
498     g_list_free(list);
499 }
500 
downloadSelectedDirs_gui(const string & target)501 void ShareBrowser::downloadSelectedDirs_gui(const string &target)
502 {
503     DirectoryListing::Directory *dir;
504     GtkTreeIter iter;
505 
506     if (gtk_tree_selection_get_selected(dirSelection, NULL, &iter))
507     {
508         dir = dirView.getValue<gpointer, DirectoryListing::Directory *>(&iter, "DL Dir");
509 
510         typedef Func2<ShareBrowser, DirectoryListing::Directory *, string> F2;
511         F2 * func = new F2(this, &ShareBrowser::downloadDir_client, dir, target);
512         WulforManager::get()->dispatchClientFunc(func);
513     }
514 }
515 
popupFileMenu_gui()516 void ShareBrowser::popupFileMenu_gui()
517 {
518     GtkWidget *menuItem;
519 
520     // Clean menus
521     gtk_container_foreach(GTK_CONTAINER(getWidget("fileDownloadMenu")), (GtkCallback)gtk_widget_destroy, NULL);
522     fileUserCommandMenu->cleanMenu_gui();
523 
524     // Build file download menu
525     StringPairList spl = FavoriteManager::getInstance()->getFavoriteDirs();
526     if (!spl.empty())
527     {
528         for (StringPairIter i = spl.begin(); i != spl.end(); ++i)
529         {
530             menuItem = gtk_menu_item_new_with_label(i->second.c_str());
531             g_object_set_data_full(G_OBJECT(menuItem), "fav", g_strdup(i->first.c_str()), g_free);
532             g_signal_connect(menuItem, "activate", G_CALLBACK(onDownloadFavoriteClicked_gui), (gpointer)this);
533             gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("fileDownloadMenu")), menuItem);
534         }
535         menuItem = gtk_separator_menu_item_new();
536         gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("fileDownloadMenu")), menuItem);
537     }
538 
539     menuItem = gtk_menu_item_new_with_label(_("Browse..."));
540     g_signal_connect(menuItem, "activate", G_CALLBACK(onDownloadToClicked_gui), (gpointer)this);
541     gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("fileDownloadMenu")), menuItem);
542 
543     // Build user command menu
544     StringList hubs = WulforUtil::getHubAddress(listing.getUser().user->getCID(), "");
545     fileUserCommandMenu->addHub(hubs);
546     GtkTreeIter iter;
547     GList *list = gtk_tree_selection_get_selected_rows(fileSelection, NULL);
548     string cid = listing.getUser().user->getCID().toBase32();
549 
550     for (GList *i = list; i; i = i->next)
551     {
552         GtkTreePath *path = (GtkTreePath *)i->data;
553         if (gtk_tree_model_get_iter(GTK_TREE_MODEL(fileStore), &iter, path))
554         {
555             string filepath;
556             string fileOrder = fileView.getString(&iter, "File Order");
557             gpointer ptr = fileView.getValue<gpointer>(&iter, "DL File");
558 
559             if (fileOrder[0] == 'd')
560             {
561                 DirectoryListing::Directory *dir = (DirectoryListing::Directory *)ptr;
562                 filepath = listing.getPath(dir->getParent());
563             }
564             else
565             {
566                 DirectoryListing::File *file = (DirectoryListing::File *)ptr;
567                 filepath = listing.getPath(file);
568             }
569 
570             fileUserCommandMenu->addFile(cid,
571                 fileView.getString(&iter, _("Filename")),
572                 filepath,
573                 fileView.getValue<int64_t>(&iter, "Size Order"),
574                 fileView.getString(&iter, _("TTH")));
575         }
576         gtk_tree_path_free(path);
577     }
578     g_list_free(list);
579     fileUserCommandMenu->buildMenu_gui();
580 
581     gtk_menu_popup(GTK_MENU(getWidget("fileMenu")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
582     gtk_widget_show_all(getWidget("fileMenu"));
583 }
584 
popupDirMenu_gui()585 void ShareBrowser::popupDirMenu_gui()
586 {
587     GtkWidget *menuItem;
588 
589     // Clean menus
590     gtk_container_foreach(GTK_CONTAINER(getWidget("dirDownloadMenu")), (GtkCallback)gtk_widget_destroy, NULL);
591     dirUserCommandMenu->cleanMenu_gui();
592 
593     StringPairList spl = FavoriteManager::getInstance()->getFavoriteDirs();
594     if (!spl.empty())
595     {
596         for (StringPairIter i = spl.begin(); i != spl.end(); ++i)
597         {
598             menuItem = gtk_menu_item_new_with_label(i->second.c_str());
599             g_object_set_data_full(G_OBJECT(menuItem), "fav", g_strdup(i->first.c_str()), g_free);
600             g_signal_connect(menuItem, "activate", G_CALLBACK(onDownloadFavoriteDirClicked_gui), (gpointer)this);
601             gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("dirDownloadMenu")), menuItem);
602         }
603         menuItem = gtk_separator_menu_item_new();
604         gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("dirDownloadMenu")), menuItem);
605     }
606 
607     menuItem = gtk_menu_item_new_with_label(_("Browse..."));
608     g_signal_connect(menuItem, "activate", G_CALLBACK(onDownloadDirToClicked_gui), (gpointer)this);
609     gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("dirDownloadMenu")), menuItem);
610 
611     // Add user commands.
612     GtkTreeIter iter;
613     if (gtk_tree_selection_get_selected(dirSelection, NULL, &iter))
614     {
615         string filename;
616         string filepath;
617         string cid = listing.getUser().user->getCID().toBase32();
618         StringList hubs = WulforUtil::getHubAddress(listing.getUser().user->getCID(), "");
619         DirectoryListing::Directory *dir = dirView.getValue<DirectoryListing::Directory *>(&iter, "DL Dir");
620 
621         if (dir != listing.getRoot())
622         {
623             filename = dirView.getString(&iter, _("Dir"));
624             filepath = listing.getPath(dir->getParent());
625         }
626         dirUserCommandMenu->addFile(cid, filename, filepath);
627         dirUserCommandMenu->addHub(hubs);
628         dirUserCommandMenu->buildMenu_gui();
629     }
630 
631     gtk_menu_popup(GTK_MENU(getWidget("dirMenu")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
632     gtk_widget_show_all(getWidget("dirMenu"));
633 }
634 
635 /*
636  * Searches the directories iteratively for the requested pattern. Uses a pre-order
637  * traversal method, with the exception that it searches the parent's dir name first.
638  * Instead of keeping track of the last directory its search ended at, it counts
639  * the number of matches and re-searches the listing, skipping matches until it
640  * reaches the newest one. Slightly slower, but simpler.
641  */
find_gui()642 void ShareBrowser::find_gui()
643 {
644     string name;
645     bool findLeafNode = TRUE;
646     int cursorPos, hits = 0;
647     DirectoryListing::Directory *dir;
648     DirectoryListing::File::Iter file;
649     GtkTreeIter iter;
650     GtkTreeModel *m = GTK_TREE_MODEL(dirStore);
651     GtkTreePath *dirPath = gtk_tree_path_new_first();
652 
653     if (!gtk_tree_path_get_depth(dirPath) || !gtk_tree_model_get_iter(m, &iter, dirPath))
654     {
655         gtk_tree_path_free(dirPath);
656         return;
657     }
658 
659     gint sortColumn;
660     GtkSortType sortType;
661     gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(fileStore), &sortColumn, &sortType);
662     if (sortColumn != fileView.col("File Order") || sortType != GTK_SORT_ASCENDING)
663     {
664         gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(fileStore), fileView.col("File Order"), GTK_SORT_ASCENDING);
665         gtk_tree_view_column_set_sort_indicator(gtk_tree_view_get_column(fileView.get(), fileView.col(_("Filename"))), TRUE);
666     }
667 
668     while (TRUE)
669     {
670         // Drill down until we reach a leaf node (e.g. a dir with no child dirs).
671         if (findLeafNode)
672         {
673             do
674             {
675                 name = Text::toLower(dirView.getString(&iter, _("Dir")));
676                 // We found a matching directory name.
677                 if (name.find(search, 0) != string::npos && hits++ == skipHits)
678                 {
679                     skipHits = hits;
680                     gtk_tree_view_expand_to_path(dirView.get(), dirPath);
681                     gtk_tree_view_set_cursor(dirView.get(), dirPath, NULL, FALSE);
682                     dir = dirView.getValue<gpointer, DirectoryListing::Directory *>(&iter, "DL Dir");
683                     updateFiles_gui(dir);
684                     gtk_widget_grab_focus(GTK_WIDGET(dirView.get()));
685                     updateFileView = FALSE;
686                     gtk_tree_path_free(dirPath);
687                     setStatus_gui("mainStatus", _("Found a match"));
688                     return;
689                 }
690                 gtk_tree_path_down(dirPath);
691             }
692             while (gtk_tree_model_get_iter(m, &iter, dirPath));
693         }
694 
695         // Come back up one directory. If we can't, then we've returned to the root and are done.
696         if (!gtk_tree_path_up(dirPath) || !gtk_tree_path_get_depth(dirPath) ||
697             !gtk_tree_model_get_iter(m, &iter, dirPath))
698         {
699             setStatus_gui("mainStatus", _("No matches"));
700             gtk_tree_path_free(dirPath);
701             return;
702         }
703 
704         // Search the files that are contained in this directory.
705         dir = dirView.getValue<gpointer, DirectoryListing::Directory *>(&iter, "DL Dir");
706         std::sort(dir->files.begin(), dir->files.end(), DirectoryListing::File::FileSort());
707 
708         for (file = dir->files.begin(), cursorPos = dir->directories.size(); file != dir->files.end(); ++file, ++cursorPos)
709         {
710             name = Text::toLower((*file)->getName());
711 
712             // We found a matching file. Update the cursors and the fileView if necessary.
713             if (name.find(search, 0) != string::npos && hits++ == skipHits)
714             {
715                 if (updateFileView)
716                 {
717                     gtk_tree_view_expand_to_path(dirView.get(), dirPath);
718                     gtk_tree_view_set_cursor(dirView.get(), dirPath, NULL, FALSE);
719                     updateFiles_gui(dir);
720                     updateFileView = FALSE;
721                 }
722 
723                 skipHits = hits;
724                 // Keeping track of the current index allows us to quickly get the path to the file.
725                 GtkTreePath *path = gtk_tree_path_new_from_string(Util::toString(cursorPos).c_str());
726                 gtk_tree_view_set_cursor(fileView.get(), path, NULL, FALSE);
727                 gtk_widget_grab_focus(GTK_WIDGET(fileView.get()));
728                 gtk_tree_path_free(path);
729                 gtk_tree_path_free(dirPath);
730                 setStatus_gui("mainStatus", _("Found a match"));
731                 return;
732             }
733         }
734         updateFileView = TRUE;
735 
736         // Determine if we are to go to the next sibling or back to the parent dir.
737         gtk_tree_path_next(dirPath);
738         if (!gtk_tree_model_get_iter(m, &iter, dirPath))
739             findLeafNode = FALSE;
740         else
741             findLeafNode = TRUE;
742     }
743 }
744 
onButtonPressed_gui(GtkWidget * widget,GdkEventButton * event,gpointer data)745 gboolean ShareBrowser::onButtonPressed_gui(GtkWidget *widget, GdkEventButton *event, gpointer data)
746 {
747     ShareBrowser *sb = (ShareBrowser *)data;
748     sb->oldType = event->type;
749 
750     if (event->button == 3)
751     {
752         GtkTreePath *path;
753 
754         if (gtk_tree_view_get_path_at_pos(sb->fileView.get(), (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL))
755         {
756             bool selected = gtk_tree_selection_path_is_selected(sb->fileSelection, path);
757             gtk_tree_path_free(path);
758 
759             if (selected)
760                 return TRUE;
761         }
762     }
763 
764     return FALSE;
765 }
766 
onFileButtonReleased_gui(GtkWidget * widget,GdkEventButton * event,gpointer data)767 gboolean ShareBrowser::onFileButtonReleased_gui(GtkWidget *widget, GdkEventButton *event, gpointer data)
768 {
769     ShareBrowser *sb = (ShareBrowser *)data;
770     gint count = gtk_tree_selection_count_selected_rows(sb->fileSelection);
771 
772     if (count > 0 && event->type == GDK_BUTTON_RELEASE && event->button == 3)
773         sb->popupFileMenu_gui();
774     else if (count == 1 && sb->oldType == GDK_2BUTTON_PRESS && event->button == 1)
775         sb->fileViewSelected_gui();
776 
777     return FALSE;
778 }
779 
onFileKeyReleased_gui(GtkWidget * widget,GdkEventKey * event,gpointer data)780 gboolean ShareBrowser::onFileKeyReleased_gui(GtkWidget *widget, GdkEventKey *event, gpointer data)
781 {
782     ShareBrowser *sb = (ShareBrowser *)data;
783     gint count = gtk_tree_selection_count_selected_rows(sb->fileSelection);
784 
785     if (count > 0 && (event->keyval == GDK_Menu || (event->keyval == GDK_F10 && event->state & GDK_SHIFT_MASK)))
786         sb->popupFileMenu_gui();
787     else if (count == 1 && (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
788         sb->fileViewSelected_gui();
789 
790     return FALSE;
791 }
792 
onDirButtonReleased_gui(GtkWidget * widget,GdkEventButton * event,gpointer data)793 gboolean ShareBrowser::onDirButtonReleased_gui(GtkWidget *widget, GdkEventButton *event, gpointer data)
794 {
795     ShareBrowser *sb = (ShareBrowser *)data;
796     GtkTreeIter iter;
797     gpointer ptr;
798 
799     if (!gtk_tree_selection_get_selected(sb->dirSelection, NULL, &iter))
800         return FALSE;
801 
802     if (!sb->isFull()) sb->viewPartial_gui();
803 
804     if (event->button == 1 && sb->oldType == GDK_2BUTTON_PRESS)
805     {
806         GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(sb->dirStore), &iter);
807         if (gtk_tree_view_row_expanded(sb->dirView.get(), path))
808             gtk_tree_view_collapse_row(sb->dirView.get(), path);
809         else
810             gtk_tree_view_expand_row(sb->dirView.get(), path, FALSE);
811         gtk_tree_path_free(path);
812     }
813     else if (event->button == 1 && event->type == GDK_BUTTON_RELEASE)
814     {
815         ptr = sb->dirView.getValue<gpointer>(&iter, "DL Dir");
816         sb->updateFiles_gui((DirectoryListing::Directory *)ptr);
817     }
818     else if (event->button == 3 && event->type == GDK_BUTTON_RELEASE)
819     {
820         ptr = sb->dirView.getValue<gpointer>(&iter, "DL Dir");
821         sb->updateFiles_gui((DirectoryListing::Directory *)ptr);
822         sb->popupDirMenu_gui();
823     }
824 
825     return FALSE;
826 }
827 
onDirKeyReleased_gui(GtkWidget * widget,GdkEventKey * event,gpointer data)828 gboolean ShareBrowser::onDirKeyReleased_gui(GtkWidget *widget, GdkEventKey *event, gpointer data)
829 {
830     ShareBrowser *sb = (ShareBrowser *)data;
831     GtkTreeIter iter;
832     gpointer ptr;
833 
834     if (!gtk_tree_selection_get_selected(sb->dirSelection, NULL, &iter))
835         return FALSE;
836 
837     if (!sb->isFull()) sb->viewPartial_gui();
838 
839     if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter || event->keyval == GDK_Right || event->keyval == GDK_Left)
840     {
841         GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(sb->dirStore), &iter);
842         if (gtk_tree_view_row_expanded(sb->dirView.get(), path))
843             gtk_tree_view_collapse_row(sb->dirView.get(), path);
844         else
845             gtk_tree_view_expand_row(sb->dirView.get(), path, FALSE);
846         gtk_tree_path_free(path);
847     }
848     else if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
849         event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
850     {
851         ptr = sb->dirView.getValue<gpointer>(&iter, "DL Dir");
852         sb->updateFiles_gui((DirectoryListing::Directory *)ptr);
853     }
854     else if (event->keyval == GDK_Menu || (event->keyval == GDK_F10 && event->state & GDK_SHIFT_MASK))
855     {
856         ptr = sb->dirView.getValue<gpointer>(&iter, "DL Dir");
857         sb->updateFiles_gui((DirectoryListing::Directory *)ptr);
858         sb->popupDirMenu_gui();
859     }
860 
861     return FALSE;
862 }
863 
onMatchButtonClicked_gui(GtkWidget * widget,gpointer data)864 void ShareBrowser::onMatchButtonClicked_gui(GtkWidget *widget, gpointer data)
865 {
866     typedef Func0<ShareBrowser> F0;
867     F0 *f0 = new F0((ShareBrowser*)data, &ShareBrowser::matchQueue_client);
868     WulforManager::get()->dispatchClientFunc(f0);
869 }
870 
onFindButtonClicked_gui(GtkWidget * widget,gpointer data)871 void ShareBrowser::onFindButtonClicked_gui(GtkWidget *widget, gpointer data)
872 {
873     ShareBrowser *sb = (ShareBrowser *)data;
874 
875     gtk_widget_grab_focus(GTK_WIDGET(sb->getWidget("findEntry")));
876     gint response = gtk_dialog_run(GTK_DIALOG(sb->getWidget("findDialog")));
877 
878     // Fix crash, if the dialog gets programmatically destroyed.
879     if (response == GTK_RESPONSE_NONE)
880         return;
881 
882     gtk_widget_hide(sb->getWidget("findDialog"));
883 
884     if (response == GTK_RESPONSE_OK)
885     {
886         string text = gtk_entry_get_text(GTK_ENTRY(sb->getWidget("findEntry")));
887         if (!text.empty())
888         {
889             sb->search = text;
890             sb->skipHits = 0;
891             sb->find_gui();
892         }
893         else
894         {
895             sb->setStatus_gui("mainStatus", _("No matches"));
896         }
897     }
898 }
899 
onNextButtonClicked_gui(GtkWidget * widget,gpointer data)900 void ShareBrowser::onNextButtonClicked_gui(GtkWidget *widget, gpointer data)
901 {
902     ShareBrowser *sb = (ShareBrowser *)data;
903     if (!sb->search.empty())
904         sb->find_gui();
905     else
906         sb->setStatus_gui("mainStatus", _("No search text entered"));
907 }
908 
onDownloadClicked_gui(GtkMenuItem * item,gpointer data)909 void ShareBrowser::onDownloadClicked_gui(GtkMenuItem *item, gpointer data)
910 {
911     ShareBrowser *sb = (ShareBrowser *)data;
912     sb->downloadSelectedFiles_gui(Text::fromUtf8(SETTING(DOWNLOAD_DIRECTORY)));
913 }
914 
onDownloadToClicked_gui(GtkMenuItem * item,gpointer data)915 void ShareBrowser::onDownloadToClicked_gui(GtkMenuItem *item, gpointer data)
916 {
917     ShareBrowser *sb = (ShareBrowser *)data;
918 
919     gint response = gtk_dialog_run(GTK_DIALOG(sb->getWidget("dirChooserDialog")));
920 
921     // Fix crash, if the dialog gets programmatically destroyed.
922     if (response == GTK_RESPONSE_NONE)
923         return;
924 
925     gtk_widget_hide(sb->getWidget("dirChooserDialog"));
926 
927     if (response == GTK_RESPONSE_OK)
928     {
929         gchar *temp = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(sb->getWidget("dirChooserDialog")));
930         if (temp)
931         {
932             string path = Text::toUtf8(temp);
933             g_free(temp);
934             if (path[path.length() - 1] != PATH_SEPARATOR)
935                 path += PATH_SEPARATOR;
936 
937             sb->downloadSelectedFiles_gui(path);
938         }
939     }
940 }
941 
onDownloadFavoriteClicked_gui(GtkMenuItem * item,gpointer data)942 void ShareBrowser::onDownloadFavoriteClicked_gui(GtkMenuItem *item, gpointer data)
943 {
944     ShareBrowser *sb = (ShareBrowser *)data;
945     string target = string((gchar *)g_object_get_data(G_OBJECT(item), "fav"));
946     sb->downloadSelectedFiles_gui(target);
947 }
948 
onDownloadDirClicked_gui(GtkMenuItem * item,gpointer data)949 void ShareBrowser::onDownloadDirClicked_gui(GtkMenuItem *item, gpointer data)
950 {
951     ShareBrowser *sb = (ShareBrowser *)data;
952     sb->downloadSelectedDirs_gui(Text::fromUtf8(SETTING(DOWNLOAD_DIRECTORY)));
953 }
954 
onDownloadDirToClicked_gui(GtkMenuItem * item,gpointer data)955 void ShareBrowser::onDownloadDirToClicked_gui(GtkMenuItem *item, gpointer data)
956 {
957     ShareBrowser *sb = (ShareBrowser *)data;
958 
959     gint response = gtk_dialog_run(GTK_DIALOG(sb->getWidget("dirChooserDialog")));
960 
961     // Fix crash, if the dialog gets programmatically destroyed.
962     if (response == GTK_RESPONSE_NONE)
963         return;
964 
965     gtk_widget_hide(sb->getWidget("dirChooserDialog"));
966 
967     if (response == GTK_RESPONSE_OK)
968     {
969         gchar *temp = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(sb->getWidget("dirChooserDialog")));
970         if (temp)
971         {
972             string path = Text::toUtf8(temp);
973             g_free(temp);
974             if (path[path.length() - 1] != PATH_SEPARATOR)
975                 path += PATH_SEPARATOR;
976 
977             sb->downloadSelectedDirs_gui(path);
978         }
979     }
980 }
981 
onDownloadFavoriteDirClicked_gui(GtkMenuItem * item,gpointer data)982 void ShareBrowser::onDownloadFavoriteDirClicked_gui(GtkMenuItem *item, gpointer data)
983 {
984     ShareBrowser *sb = (ShareBrowser *)data;
985     string target = string((gchar *)g_object_get_data(G_OBJECT(item), "fav"));
986     sb->downloadSelectedDirs_gui(target);
987 }
988 
onSearchAlternatesClicked_gui(GtkMenuItem * item,gpointer data)989 void ShareBrowser::onSearchAlternatesClicked_gui(GtkMenuItem *item, gpointer data)
990 {
991     ShareBrowser *sb = (ShareBrowser *)data;
992     GtkTreeIter iter;
993     GtkTreePath *path;
994     string fileOrder;
995     Search *s;
996     DirectoryListing::File *file;
997     GList *list = gtk_tree_selection_get_selected_rows(sb->fileSelection, NULL);
998 
999     for (GList *i = list; i; i = i->next)
1000     {
1001         path = (GtkTreePath *)i->data;
1002         if (gtk_tree_model_get_iter(GTK_TREE_MODEL(sb->fileStore), &iter, path))
1003         {
1004             fileOrder = sb->fileView.getString(&iter, "File Order");
1005 
1006             if (fileOrder[0] == 'f')
1007             {
1008                 file = sb->fileView.getValue<gpointer, DirectoryListing::File *>(&iter, "DL File");
1009                 s = WulforManager::get()->getMainWindow()->addSearch_gui();
1010                 s->putValue_gui(file->getTTH().toBase32(), 0, SearchManager::SIZE_DONTCARE, SearchManager::TYPE_TTH);
1011             }
1012         }
1013         gtk_tree_path_free(path);
1014     }
1015     g_list_free(list);
1016 }
1017 
onCopyMagnetClicked_gui(GtkMenuItem * item,gpointer data)1018 void ShareBrowser::onCopyMagnetClicked_gui(GtkMenuItem* item, gpointer data)
1019 {
1020     ShareBrowser *sb = (ShareBrowser *)data;
1021     GtkTreeIter iter;
1022     GtkTreePath *path;
1023     int64_t size;
1024     string magnets, magnet, filename, tth;
1025     GList *list = gtk_tree_selection_get_selected_rows(sb->fileSelection, NULL);
1026 
1027     for (GList *i = list; i; i = i->next)
1028     {
1029         path = (GtkTreePath *)i->data;
1030         if (gtk_tree_model_get_iter(GTK_TREE_MODEL(sb->fileStore), &iter, path))
1031         {
1032             filename = sb->fileView.getString(&iter, _("Filename"));
1033             size = sb->fileView.getValue<int64_t>(&iter, "Size Order");
1034             tth = sb->fileView.getString(&iter, _("TTH"));
1035             magnet = WulforUtil::makeMagnet(filename, size, tth);
1036 
1037             if (!magnet.empty())
1038             {
1039                 if (!magnets.empty())
1040                     magnets += '\n';
1041                 magnets += magnet;
1042             }
1043         }
1044         gtk_tree_path_free(path);
1045     }
1046     g_list_free(list);
1047 
1048     if (!magnets.empty())
1049         gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), magnets.c_str(), magnets.length());
1050 }
1051 
onCopyPictureClicked_gui(GtkMenuItem * item,gpointer data)1052 void ShareBrowser::onCopyPictureClicked_gui(GtkMenuItem* item, gpointer data)
1053 {
1054    ShareBrowser *sb = (ShareBrowser *)data;
1055    GtkTreeIter iter;
1056    GtkTreePath *path;
1057    int64_t size;
1058    string magnets, magnet, filename, tth;
1059    GList *list = gtk_tree_selection_get_selected_rows(sb->fileSelection, NULL);
1060 
1061    for (GList *i = list; i; i = i->next)
1062    {
1063        path = (GtkTreePath *)i->data;
1064        if (gtk_tree_model_get_iter(GTK_TREE_MODEL(sb->fileStore), &iter, path))
1065        {
1066            filename = sb->fileView.getString(&iter, _("Filename"));
1067            size = sb->fileView.getValue<int64_t>(&iter, "Size Order");
1068            tth = sb->fileView.getString(&iter, _("TTH"));
1069            magnet = WulforUtil::makeMagnet(filename, size, tth);
1070 
1071            if (!magnet.empty())
1072            {
1073                magnet = "[img]" + magnet + "[/img]";
1074                if (!magnets.empty())
1075                    magnets += '\n';
1076                magnets += magnet;
1077            }
1078        }
1079        gtk_tree_path_free(path);
1080    }
1081    g_list_free(list);
1082 
1083    if (!magnets.empty())
1084        gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), magnets.c_str(), magnets.length());
1085 }
1086 
downloadFile_client(DirectoryListing::File * file,string target)1087 void ShareBrowser::downloadFile_client(DirectoryListing::File *file, string target)
1088 {
1089     try
1090     {
1091         listing.download(file, target, FALSE, FALSE);
1092     }
1093     catch (const Exception& e)
1094     {
1095         typedef Func2<ShareBrowser, string, string> F2;
1096         F2 *func = new F2(this, &ShareBrowser::setStatus_gui, "mainStatus", e.getError());
1097         WulforManager::get()->dispatchGuiFunc(func);
1098     }
1099 }
1100 
downloadDir_client(DirectoryListing::Directory * dir,string target)1101 void ShareBrowser::downloadDir_client(DirectoryListing::Directory *dir, string target)
1102 {
1103     try
1104     {
1105         listing.download(dir, target, FALSE);
1106     }
1107     catch (const Exception& e)
1108     {
1109         typedef Func2<ShareBrowser, string, string> F2;
1110         F2 *func = new F2(this, &ShareBrowser::setStatus_gui, "mainStatus", e.getError());
1111         WulforManager::get()->dispatchGuiFunc(func);
1112     }
1113 }
1114 
matchQueue_client()1115 void ShareBrowser::matchQueue_client()
1116 {
1117     int matched = QueueManager::getInstance()->matchListing(listing);
1118     string message = _("Matched ") + Util::toString(matched) + _(" files");
1119 
1120     typedef Func2<ShareBrowser, string, string> F2;
1121     F2 *f = new F2(this, &ShareBrowser::setStatus_gui, "mainStatus", message);
1122     WulforManager::get()->dispatchGuiFunc(f);
1123 }
onDirGet(GtkMenuItem * item,gpointer data)1124 void ShareBrowser::onDirGet(GtkMenuItem* item, gpointer data)
1125 {
1126     ShareBrowser *sb=(ShareBrowser*)data;
1127     GList *list = gtk_tree_selection_get_selected_rows(sb->fileSelection, NULL);
1128     GtkTreePath *path;
1129     GtkTreeIter iter;
1130     string name,fullpath;
1131     DirectoryListing::File *filed;
1132 
1133     for (GList *i = list;i;i=i->next)
1134     {
1135         path = (GtkTreePath *)i->data;
1136         if (gtk_tree_model_get_iter(GTK_TREE_MODEL(sb->fileStore), &iter, path))
1137         {
1138             filed = sb->fileView.getValue<gpointer, DirectoryListing::File *>(&iter, "DL File");
1139 
1140             ItemInfo* ii= new ItemInfo(filed);
1141             if(ii->type == ItemInfo::FILE)
1142             {
1143                 if(!ii->file->getAdls())return;
1144                 DirectoryListing::Directory *dir=ii->file->getParent();
1145                 while( dir && (dir != sb->listing.getRoot()))
1146                 {
1147                     fullpath=dir->getName()+PATH_SEPARATOR+fullpath;
1148                     dir=dir->getParent();
1149                 }
1150             }
1151             else if(ii->type == ItemInfo::DIRECTORY)
1152             {
1153                 if(!(ii->dir->getAdls()) && (ii->dir->getParent() != sb->listing.getRoot()))
1154                     return;
1155                 fullpath = Text::toT(((DirectoryListing::AdlDirectory*)ii->dir)->getFullPath());
1156             }
1157         }
1158     }
1159     sb->openDir_gui(fullpath);
1160 }
1161 
compareItems(ItemInfo * a,ItemInfo * b,int col)1162 int ShareBrowser::ItemInfo::compareItems(ItemInfo* a, ItemInfo* b, int col) {
1163     if(a->type == DIRECTORY) {
1164         if(b->type == DIRECTORY) {
1165             switch(col) {
1166                 case COLUMN_EXACTSIZE: return compare(a->dir->getTotalSize(), b->dir->getTotalSize());
1167                 case COLUMN_SIZE: return compare(a->dir->getTotalSize(), b->dir->getTotalSize());
1168                 default: break; //strcmp(a->columns[col].c_str(), b->columns[col].c_str());
1169             }
1170         } else {
1171             return -1;
1172         }
1173     } else if(b->type == DIRECTORY) {
1174         return 1;
1175     } else {
1176         switch(col) {
1177             case COLUMN_EXACTSIZE: return compare(a->file->getSize(), b->file->getSize());
1178             case COLUMN_SIZE: return compare(a->file->getSize(), b->file->getSize());
1179             default: break;// strcmp(a->columns[col].c_str(), b->columns[col].c_str());
1180         }
1181     }
1182 
1183     return -1;
1184 }
1185 
loadXML(string txt)1186 void ShareBrowser::loadXML(string txt)
1187 {
1188     typedef Func1<ShareBrowser,string> F1;
1189     F1 *func = new F1(this,&ShareBrowser::load,txt);
1190     WulforManager::get()->dispatchGuiFunc(func);
1191 }
1192 
load(string xml)1193 void ShareBrowser::load(string xml)
1194 {
1195     // Set name of root entry to user nick.
1196     listing.getRoot()->setName(nick);
1197 
1198     GtkTreeIter iter;
1199     DirectoryListing::Directory *dirList;
1200     string path,path2;
1201     GtkTreePath *treepath;
1202     if (gtk_tree_selection_get_selected(dirSelection, NULL, &iter))
1203     {
1204         dirList = (DirectoryListing::Directory *)dirView.getValue<gpointer>(&iter,"DL Dir");
1205         path2 = dirList->getName();
1206         treepath = gtk_tree_path_copy(gtk_tree_model_get_path (GTK_TREE_MODEL(dirStore), gtk_tree_iter_copy(&iter)));
1207 
1208         //path = QueueManager::getInstance()->getListPath(listing.getUser()) + ".xml";
1209         path = Util::getListPath() + nick + user->getCID().toBase32() + ".xml.bz2";
1210         if(File::getSize(path) != -1) {
1211             // load the cached list.
1212             listing.updateXML(File(path, File::READ, File::OPEN).read());
1213         }
1214         auto base = listing.updateXML(xml);
1215         //listing.save(path);
1216         ADLSearchManager::getInstance()->matchListing(listing);
1217         gtk_tree_store_clear(dirStore);
1218         gtk_list_store_clear(fileStore);
1219         buildDirs_gui(listing.getRoot(),NULL);
1220         gtk_tree_view_expand_to_path(dirView.get(), treepath);
1221         gtk_tree_view_scroll_to_cell(dirView.get(),treepath,NULL,FALSE,0,0);
1222         gtk_tree_selection_select_path(dirSelection,treepath);
1223         updateFiles_gui(dirList);
1224     }
1225 }
1226 
viewPartial_gui()1227 void ShareBrowser::viewPartial_gui()
1228 {
1229     GtkTreeIter iter;
1230     DirectoryListing::Directory *dirList;
1231     if (gtk_tree_selection_get_selected(dirSelection, NULL, &iter))
1232     {
1233         dirList = (DirectoryListing::Directory *)dirView.getValue<gpointer>(&iter,"DL Dir");
1234         typedef Func1<ShareBrowser, DirectoryListing::Directory*> F1;
1235         F1 *func = new F1(this,&ShareBrowser::downloadChangedDir,dirList);
1236         WulforManager::get()->dispatchClientFunc(func);
1237     }
1238 }
1239 
1240 
downloadChangedDir(DirectoryListing::Directory * d)1241 void ShareBrowser::downloadChangedDir(DirectoryListing::Directory* d) {
1242     if(!d->getComplete()) {
1243         dcdebug("Directory %s incomplete, downloading...\n", d->getName().c_str());
1244         if(listing.getUser().user->isOnline()) {
1245             try {
1246                 QueueManager::getInstance()->addList(listing.getUser(), QueueItem::FLAG_PARTIAL_LIST, listing.getPath(d));
1247             } catch(const QueueException& e) { }
1248         } else {
1249             setStatus_gui("mainStatus","User went offline");
1250         }
1251     }
1252 }
1253 /*Many code from orginal DC++*/
1254