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 "WulforUtil.hh"
23 #include <glib/gi18n.h>
24 #include <glib/gstdio.h>
25 #include <dcpp/ClientManager.h>
26 #include <dcpp/Util.h>
27 #include <dcpp/StringTokenizer.h>
28 #include <iostream>
29 #include <arpa/inet.h>
30 #include <fcntl.h>
31 #include "settingsmanager.hh"
32 #include "dcpp/StringTokenizer.h"
33 #ifdef HAVE_IFADDRS_H
34 #include <ifaddrs.h>
35 #include <net/if.h>
36 #endif
37 #include "extra/magnet.h"
38
39 using namespace std;
40 using namespace dcpp;
41
42 const string WulforUtil::ENCODING_LOCALE = _("System default");
43 vector<string> WulforUtil::charsets;
44 const string WulforUtil::magnetSignature = "magnet:?";
45 GtkIconFactory* WulforUtil::iconFactory = NULL;
46
splitString(const string & str,const string & delimiter)47 vector<int> WulforUtil::splitString(const string &str, const string &delimiter)
48 {
49 string::size_type loc, len, pos = 0;
50 vector<int> array;
51
52 if (!str.empty() && !delimiter.empty())
53 {
54 while ((loc = str.find(delimiter, pos)) != string::npos)
55 {
56 len = loc - pos;
57 array.push_back(Util::toInt(str.substr(pos, len)));
58 pos = loc + delimiter.size();
59 }
60 len = str.size() - pos;
61 array.push_back(Util::toInt(str.substr(pos, len)));
62 }
63 return array;
64 }
65
linuxSeparator(const string & ps)66 string WulforUtil::linuxSeparator(const string &ps)
67 {
68 string str = ps;
69 for (auto it = str.begin(); it != str.end(); ++it)
70 if ((*it) == '\\')
71 (*it) = '/';
72 return str;
73 }
74
windowsSeparator(const string & ps)75 string WulforUtil::windowsSeparator(const string &ps)
76 {
77 string str = ps;
78 for (auto it = str.begin(); it != str.end(); ++it)
79 if ((*it) == '/')
80 (*it) = '\\';
81 return str;
82 }
83
getLocalIPs()84 vector<string> WulforUtil::getLocalIPs()
85 {
86 vector<string> addresses;
87
88 #ifdef HAVE_IFADDRS_H
89 struct ifaddrs *ifap;
90
91 if (getifaddrs(&ifap) == 0)
92 {
93 for (struct ifaddrs *i = ifap; i ; i = i->ifa_next)
94 {
95 struct sockaddr *sa = i->ifa_addr;
96
97 // If the interface is up, is not a loopback and it has an address
98 if ((i->ifa_flags & IFF_UP) && !(i->ifa_flags & IFF_LOOPBACK) && sa)
99 {
100 void* src = NULL;
101 socklen_t len;
102
103 // IPv4 address
104 if (sa->sa_family == AF_INET)
105 {
106 struct sockaddr_in* sai = (struct sockaddr_in*)sa;
107 src = (void*) &(sai->sin_addr);
108 len = INET_ADDRSTRLEN;
109 }
110 // IPv6 address
111 else if (sa->sa_family == AF_INET6)
112 {
113 struct sockaddr_in6* sai6 = (struct sockaddr_in6*)sa;
114 src = (void*) &(sai6->sin6_addr);
115 len = INET6_ADDRSTRLEN;
116 }
117
118 // Convert the binary address to a string and add it to the output list
119 if (src)
120 {
121 char address[len];
122 inet_ntop(sa->sa_family, src, address, len);
123 addresses.push_back(address);
124 }
125 }
126 }
127 freeifaddrs(ifap);
128 }
129 #endif
130
131 return addresses;
132 }
133
134
getNicks(const string & cid,const string & hintUrl)135 string WulforUtil::getNicks(const string &cid, const string& hintUrl)
136 {
137 return getNicks(CID(cid), hintUrl);
138 }
139
getNicks(const CID & cid,const string & hintUrl)140 string WulforUtil::getNicks(const CID& cid, const string& hintUrl)
141 {
142 return Util::toString(ClientManager::getInstance()->getNicks(cid, hintUrl));
143 }
144
getNicks(const UserPtr & user,const string & hintUrl)145 string WulforUtil::getNicks(const UserPtr& user, const string& hintUrl)
146 {
147 return getNicks(user->getCID(), hintUrl);
148 }
149
getHubNames(const string & cid,const string & hintUrl)150 string WulforUtil::getHubNames(const string &cid, const string& hintUrl)
151 {
152 return getHubNames(CID(cid), hintUrl);
153 }
154
getHubNames(const CID & cid,const string & hintUrl)155 string WulforUtil::getHubNames(const CID& cid, const string& hintUrl)
156 {
157 StringList hubs = ClientManager::getInstance()->getHubNames(cid, hintUrl);
158 if (hubs.empty())
159 return _("Offline");
160 else
161 return Util::toString(hubs);
162 }
163
getHubNames(const UserPtr & user,const string & hintUrl)164 string WulforUtil::getHubNames(const UserPtr& user, const string& hintUrl)
165 {
166 return getHubNames(user->getCID(), hintUrl);
167 }
168
getHubAddress(const CID & cid,const string & hintUrl)169 StringList WulforUtil::getHubAddress(const CID& cid, const string& hintUrl)
170 {
171 return ClientManager::getInstance()->getHubs(cid, hintUrl);
172 }
173
getHubAddress(const UserPtr & user,const string & hintUrl)174 StringList WulforUtil::getHubAddress(const UserPtr& user, const string& hintUrl)
175 {
176 return getHubAddress(user->getCID(), hintUrl);
177 }
178
getTextFromMenu(GtkMenuItem * item)179 string WulforUtil::getTextFromMenu(GtkMenuItem *item)
180 {
181 string text;
182 GtkWidget *child = gtk_bin_get_child(GTK_BIN(item));
183
184 if (child && GTK_IS_LABEL(child))
185 text = gtk_label_get_text(GTK_LABEL(child));
186
187 return text;
188 }
189
getCharsets()190 vector<string>& WulforUtil::getCharsets()
191 {
192 if (charsets.empty())
193 {
194 charsets.push_back(ENCODING_LOCALE);
195 //charsets.push_back(_("UTF-8 (Unicode)"));
196 //charsets.push_back(_("CP1252 (Western Europe)"));
197 //charsets.push_back(_("CP1250 (Central Europe)"));
198 //charsets.push_back(_("ISO-8859-2 (Central Europe)"));
199 //charsets.push_back(_("ISO-8859-7 (Greek)"));
200 //charsets.push_back(_("ISO-8859-8 (Hebrew)"));
201 //charsets.push_back(_("ISO-8859-9 (Turkish)"));
202 //charsets.push_back(_("ISO-2022-JP (Japanese)"));
203 //charsets.push_back(_("SJIS (Japanese)"));
204 //charsets.push_back(_("CP949 (Korean)"));
205 //charsets.push_back(_("KOI8-R (Cyrillic)"));
206 //charsets.push_back(_("CP1251 (Cyrillic)"));
207 //charsets.push_back(_("CP1256 (Arabic)"));
208 //charsets.push_back(_("CP1257 (Baltic)"));
209 //charsets.push_back(_("GB18030 (Chinese)"));
210 //charsets.push_back(_("TIS-620 (Thai)"));
211 charsets.push_back(_("UTF-8"));
212 charsets.push_back(_("CP1252"));
213 charsets.push_back(_("CP1250"));
214 charsets.push_back(_("ISO-8859-2"));
215 charsets.push_back(_("ISO-8859-7"));
216 charsets.push_back(_("ISO-8859-8"));
217 charsets.push_back(_("ISO-8859-9"));
218 charsets.push_back(_("ISO-2022-JP"));
219 charsets.push_back(_("SJIS"));
220 charsets.push_back(_("CP949"));
221 charsets.push_back(_("KOI8-R"));
222 charsets.push_back(_("CP1251"));
223 charsets.push_back(_("CP1256"));
224 charsets.push_back(_("CP1257"));
225 charsets.push_back(_("GB18030"));
226 charsets.push_back(_("TIS-620"));
227 }
228 return charsets;
229 }
230
openURI(const string & uri)231 void WulforUtil::openURI(const string &uri)
232 {
233 GError* error = NULL;
234 gchar *argv[3];
235 if (!SETTING(MIME_HANDLER).empty())
236 argv[0] = (gchar *)(SETTING(MIME_HANDLER)).c_str();
237 else
238 #if defined(__APPLE__)
239 argv[0] = (gchar *)"open";
240 #elif defined(_WIN32)
241 argv[0] = (gchar *)"start";
242 #else
243 argv[0] = (gchar *)"xdg-open";
244 #endif
245 argv[1] = (gchar *)Text::fromUtf8(uri).c_str();
246 argv[2] = NULL;
247
248 g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error);
249
250 if (error)
251 {
252 cerr << "Failed to open URI: " << error->message << endl;
253 g_error_free(error);
254 }
255 }
256
openURItoApp(const string & cmd)257 void WulforUtil::openURItoApp(const string &cmd)
258 {
259 GError* error = NULL;
260
261 g_spawn_command_line_async((gchar *)Text::fromUtf8(cmd).c_str(), &error);
262
263 if (error)
264 {
265 cerr << "Failed to open application: " << error->message << endl;
266 g_error_free(error);
267 }
268 }
269
colorToString(const GdkColor * color)270 string WulforUtil::colorToString(const GdkColor *color)
271 {
272 gchar strcolor[14];
273
274 g_snprintf(strcolor, sizeof(strcolor), "#%04X%04X%04X",
275 color->red, color->green, color->blue);
276 //printf("WulforUtil::colorToString{GdkColor} %s\n", strcolor);fflush(stdout);
277 return strcolor;
278 }
279
280 #if GTK_CHECK_VERSION (3,0,0)
colorToString(const GdkRGBA * color)281 string WulforUtil::colorToString(const GdkRGBA *color)
282 {
283 gchar strcolor[14];
284
285 g_snprintf(strcolor, sizeof(strcolor), "#%04X%04X%04X",
286 (uint16_t)(color->red*65535.0), (uint16_t)(color->green*65535.0), (uint16_t)(color->blue*65535.0));
287 //printf("WulforUtil::colorToString{GdkRGBA} %s\n",strcolor);fflush(stdout);
288 return strcolor;
289 }
290 #endif
291
scalePixbuf(const GdkPixbuf * pixbuf,const int width,const int height,GdkInterpType type)292 GdkPixbuf* WulforUtil::scalePixbuf(const GdkPixbuf *pixbuf, const int width, const int height, GdkInterpType type)
293 {
294 g_return_val_if_fail(pixbuf != NULL, NULL);
295 g_return_val_if_fail(width > 0, NULL);
296 g_return_val_if_fail(height > 0, NULL);
297
298 GdkPixbuf *scale = NULL;
299
300 int Width = gdk_pixbuf_get_width(pixbuf);
301 int Height = gdk_pixbuf_get_height(pixbuf);
302
303 double w, h, k;
304
305 w = (double) width / Width;
306 h = (double) height / Height;
307 k = MIN (w, h);
308
309 if (Width > width || Height > height)
310
311 scale = gdk_pixbuf_scale_simple(pixbuf, (int)(Width * k), (int)(Height * k), type);
312 else
313 scale = gdk_pixbuf_scale_simple(pixbuf, (int)(Width * k * 0.85), (int)(Height * k * 0.85), type);
314 return
315 scale;
316 }
317
makeMagnet(const string & name,const int64_t size,const string & tth)318 string WulforUtil::makeMagnet(const string &name, const int64_t size, const string &tth)
319 {
320 if (name.empty() || tth.empty())
321 return string();
322
323 // other clients can return paths with different separators, so we should catch both cases
324 string::size_type i = name.find_last_of("/\\");
325 string path = (i != string::npos) ? name.substr(i + 1) : name;
326
327 return magnetSignature + "xt=urn:tree:tiger:" + tth + "&xl=" + Util::toString(size) + "&dn=" + Util::encodeURI(path);
328 }
329
splitMagnet(const string & magnet,string & name,int64_t & size,string & tth)330 bool WulforUtil::splitMagnet(const string &magnet, string &name, int64_t &size, string &tth)
331 {
332 name = _("Unknown");
333 size = 0;
334 tth = _("Unknown");
335
336 StringMap params;
337 if (magnet::parseUri(magnet,params)) {
338 tth=params["xt"];
339 size = Util::toInt64(params["xl"]);
340 name = params["dn"];
341 return TRUE;
342 }
343 return FALSE;
344 }
345
splitMagnet(const string & magnet,string & line)346 bool WulforUtil::splitMagnet(const string &magnet, string &line)
347 {
348 string name;
349 string tth;
350 int64_t size;
351
352 if (splitMagnet(magnet, name, size, tth))
353 line = name + " (" + Util::formatBytes(size) + ")";
354 else
355 return FALSE;
356
357 return TRUE;
358 }
359
isMagnet(const string & text)360 bool WulforUtil::isMagnet(const string &text)
361 {
362 return g_ascii_strncasecmp(text.c_str(), magnetSignature.c_str(), magnetSignature.length()) == 0;
363 }
364
isLink(const string & text)365 bool WulforUtil::isLink(const string &text)
366 {
367 return g_ascii_strncasecmp(text.c_str(), "http://", 7) == 0 ||
368 g_ascii_strncasecmp(text.c_str(), "https://", 8) == 0 ||
369 g_ascii_strncasecmp(text.c_str(), "www.", 4) == 0 ||
370 g_ascii_strncasecmp(text.c_str(), "ftp://", 6) == 0 ||
371 g_ascii_strncasecmp(text.c_str(), "sftp://", 7) == 0 ||
372 g_ascii_strncasecmp(text.c_str(), "irc://", 6) == 0 ||
373 g_ascii_strncasecmp(text.c_str(), "ircs://", 7) == 0 ||
374 g_ascii_strncasecmp(text.c_str(), "im:", 3) == 0 ||
375 g_ascii_strncasecmp(text.c_str(), "mailto:", 7) == 0 ||
376 g_ascii_strncasecmp(text.c_str(), "news:", 5) == 0;
377 }
378
isHubURL(const string & text)379 bool WulforUtil::isHubURL(const string &text)
380 {
381 return g_ascii_strncasecmp(text.c_str(), "dchub://", 8) == 0 ||
382 g_ascii_strncasecmp(text.c_str(), "adc://", 6) == 0 ||
383 g_ascii_strncasecmp(text.c_str(), "adcs://", 7) == 0;
384 }
385
profileIsLocked()386 bool WulforUtil::profileIsLocked()
387 {
388 static bool profileIsLocked = false;
389
390 if (profileIsLocked)
391 return TRUE;
392
393 // We can't use Util::getConfigPath() since the core has not been started yet.
394 // Also, Util::getConfigPath() is utf8 and we need system encoding for g_open().
395 string configPath;
396 char *home = getenv("HOME");
397 #ifdef FORCE_XDG
398 const char *xdg_config_home_ = getenv("XDG_CONFIG_HOME");
399 string xdg_config_home = xdg_config_home_? Text::toUtf8(xdg_config_home_) : (Text::toUtf8(home) +"/.config");
400 xdg_config_home += "/eiskaltdc++/";
401 #else
402 string xdg_config_home = Text::toUtf8(home) + "/.eiskaltdc++/";
403 #endif
404 configPath = !xdg_config_home.empty() ? xdg_config_home : "/tmp/";
405 string profileLockingFile = configPath + "profile.lck";
406 int flags = O_WRONLY | O_CREAT;
407 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
408
409 int fd = g_open(profileLockingFile.c_str(), flags, mode);
410 if (fd != -1) // read error
411 {
412 struct flock lock;
413 lock.l_start = 0;
414 lock.l_len = 0;
415 lock.l_type = F_WRLCK;
416 lock.l_whence = SEEK_SET;
417 struct flock testlock = lock;
418
419 if (fcntl(fd, F_GETLK, &testlock) != -1) // Locking not supported
420 {
421 if (fcntl(fd, F_SETLK, &lock) == -1)
422 profileIsLocked = true;
423 }
424 }
425
426 return profileIsLocked;
427 }
428
429
getNextIter_gui(GtkTreeModel * model,GtkTreeIter * iter,bool children,bool parent)430 gboolean WulforUtil::getNextIter_gui(GtkTreeModel *model, GtkTreeIter *iter, bool children /* = TRUE */, bool parent /* = TRUE */)
431 {
432 gboolean valid = FALSE;
433 GtkTreeIter old = *iter;
434
435 if (children && gtk_tree_model_iter_has_child(model, iter))
436 {
437 valid = gtk_tree_model_iter_children(model, iter, &old);
438 }
439 else
440 {
441 valid = gtk_tree_model_iter_next(model, iter);
442 }
443
444 // Try to go up one level if next failed
445 if (!valid && parent)
446 {
447 valid = gtk_tree_model_iter_parent(model, iter, &old);
448 if (valid)
449 valid = gtk_tree_model_iter_next(model, iter);
450 }
451
452 return valid;
453 }
454
copyRow_gui(GtkListStore * store,GtkTreeIter * fromIter,int position)455 GtkTreeIter WulforUtil::copyRow_gui(GtkListStore *store, GtkTreeIter *fromIter, int position /* = -1 */)
456 {
457 GtkTreeIter toIter;
458 gtk_list_store_insert(store, &toIter, position);
459 GtkTreeModel *m = GTK_TREE_MODEL(store);
460 int count = gtk_tree_model_get_n_columns(m);
461
462 for (int col = 0; col < count; col++)
463 {
464 copyValue_gui(store, fromIter, &toIter, col);
465 }
466
467 return toIter;
468 }
469
copyValue_gui(GtkListStore * store,GtkTreeIter * fromIter,GtkTreeIter * toIter,int position)470 void WulforUtil::copyValue_gui(GtkListStore *store, GtkTreeIter *fromIter, GtkTreeIter *toIter, int position)
471 {
472 GValue value = {0, };
473 gtk_tree_model_get_value(GTK_TREE_MODEL(store), fromIter, position, &value);
474 gtk_list_store_set_value(store, toIter, position, &value);
475 g_value_unset(&value);
476 }
477
copyRow_gui(GtkTreeStore * store,GtkTreeIter * fromIter,GtkTreeIter * parent,int position)478 GtkTreeIter WulforUtil::copyRow_gui(GtkTreeStore *store, GtkTreeIter *fromIter, GtkTreeIter *parent /* = NULL */, int position /* = -1 */)
479 {
480 GtkTreeIter toIter;
481 gtk_tree_store_insert(store, &toIter, parent, position);
482 GtkTreeModel *m = GTK_TREE_MODEL(store);
483 int count = gtk_tree_model_get_n_columns(m);
484
485 for (int col = 0; col < count; col++)
486 {
487 copyValue_gui(store, fromIter, &toIter, col);
488 }
489
490 return toIter;
491 }
492
copyValue_gui(GtkTreeStore * store,GtkTreeIter * fromIter,GtkTreeIter * toIter,int position)493 void WulforUtil::copyValue_gui(GtkTreeStore *store, GtkTreeIter *fromIter, GtkTreeIter *toIter, int position)
494 {
495 GValue value = {0, };
496 gtk_tree_model_get_value(GTK_TREE_MODEL(store), fromIter, position, &value);
497 gtk_tree_store_set_value(store, toIter, position, &value);
498 g_value_unset(&value);
499 }
500
501 /*
502 * Registers either the custom icons or the GTK+ icons as stock icons in
503 * GtkIconFactory according to the user's preference. If the icons have
504 * previously been loaded, they are removed and re-added.
505 */
registerIcons()506 void WulforUtil::registerIcons()
507 {
508 // Holds a mapping of custom icon names -> stock icon names.
509 // Not all icons have stock representations.
510 WulforSettingsManager *wsm = WulforSettingsManager::getInstance();
511 map<string, string> icons;
512 icons["eiskaltdcpp"] = "eiskaltdcpp";
513 icons["icon_msg"] = wsm->getString("icon_msg");
514 icons["eiskaltdcpp-dc++"] = wsm->getString("icon-dc++");
515 icons["eiskaltdcpp-dc++-fw"] = wsm->getString("icon-dc++-fw");
516 icons["eiskaltdcpp-dc++-fw-op"] = wsm->getString("icon-dc++-fw-op");
517 icons["eiskaltdcpp-dc++-op"] = wsm->getString("icon-dc++-op");
518 icons["eiskaltdcpp-normal"] = wsm->getString("icon-normal");
519 icons["eiskaltdcpp-normal-fw"] = wsm->getString("icon-normal-fw");
520 icons["eiskaltdcpp-normal-fw-op"] = wsm->getString("icon-normal-fw-op");
521 icons["eiskaltdcpp-normal-op"] = wsm->getString("icon-normal-op");
522 icons["icon-smile"] = wsm->getString("icon-smile");
523 icons["icon-download"] = wsm->getString("icon-download");
524 icons["icon-favorite-hubs"] = wsm->getString("icon-favorite-hubs");
525 icons["icon-favorite-users"] = wsm->getString("icon-favorite-users");
526 icons["icon-finished-downloads"] = wsm->getString("icon-finished-downloads");
527 icons["icon-finished-uploads"] = wsm->getString("icon-finished-uploads");
528 icons["icon-hash"] = wsm->getString("icon-hash");
529 icons["icon-preferences"] = wsm->getString("icon-preferences");
530 icons["icon-public-hubs"] = wsm->getString("icon-public-hubs");
531 icons["icon-queue"] = wsm->getString("icon-queue");
532 icons["icon-search"] = wsm->getString("icon-search");
533 icons["icon-search-spy"] = wsm->getString("icon-search-spy");
534 icons["icon-upload"] = wsm->getString("icon-upload");
535 icons["icon-quit"] = wsm->getString("icon-quit");
536 icons["icon-connect"] = wsm->getString("icon-connect");
537 icons["icon-file"] = wsm->getString("icon-file");
538 icons["icon-directory"] = wsm->getString("icon-directory");
539 icons["icon-refresh"] = wsm->getString("icon-refresh");
540 icons["icon-reconnect"] = wsm->getString("icon-reconnect");
541 icons["icon-openlist"] = wsm->getString("icon-openlist");
542 icons["icon-own-filelist"] = wsm->getString("icon-own-filelist");
543 icons["icon-magnet"] = wsm->getString("icon-magnet");
544 icons["icon-search-adl"] = wsm->getString("icon-search-adl");
545 icons["icon-pm-online"] = wsm->getString("icon-pm-online");
546 icons["icon-pm-offline"] = wsm->getString("icon-pm-offline");
547 icons["icon-hub-online"] = wsm->getString("icon-hub-online");
548 icons["icon-hub-offline"] = wsm->getString("icon-hub-offline");
549
550 if (iconFactory)
551 {
552 gtk_icon_factory_remove_default(iconFactory);
553 iconFactory = NULL;
554 }
555
556 iconFactory = gtk_icon_factory_new();
557
558 for (auto i = icons.begin(); i != icons.end(); ++i)
559 {
560 GtkIconSource *iconSource = gtk_icon_source_new();
561 GtkIconSet *iconSet = gtk_icon_set_new();
562 gtk_icon_source_set_icon_name(iconSource, i->second.c_str());
563 gtk_icon_set_add_source(iconSet, iconSource);
564 gtk_icon_factory_add(iconFactory, i->first.c_str(), iconSet);
565 gtk_icon_source_free(iconSource);
566 gtk_icon_set_unref(iconSet);
567 }
568
569 gtk_icon_factory_add_default(iconFactory);
570 g_object_unref(iconFactory);
571 }
572