move network tools
[reactos.git] / reactos / subsys / system / ibrowser / favorites.cpp
1 /*
2 * Copyright 2004 Martin Fuchs
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library 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 GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19
20 //
21 // Explorer and Desktop clone
22 //
23 // favorites.cpp
24 //
25 // Martin Fuchs, 04.04.2004
26 //
27
28
29 #include <precomp.h>
30
31
32 String DecodeURLString(const char* s)
33 {
34 TCHAR buffer[BUFFER_LEN];
35 LPTSTR o = buffer;
36
37 for(const char* p=s; *p; ++p)
38 if (*p == '%') {
39 if (!strncmp(p+1, "20", 2)) {
40 *o++ = ' ';
41 p += 2;
42 } else
43 *o++ = *p;
44 } else
45 *o++ = *p;
46
47 return String(buffer, o-buffer);
48 }
49
50
51 /// read .URL file
52 bool Bookmark::read_url(LPCTSTR path)
53 {
54 char line[BUFFER_LEN];
55
56 tifstream in(path);
57
58 while(in.good()) {
59 in.getline(line, BUFFER_LEN);
60
61 const char* p = line;
62 while(isspace(*p))
63 ++p;
64
65 const char* keyword = p;
66 const char* eq = strchr(p, '=');
67
68 if (eq) {
69 const char* cont = eq + 1;
70 while(isspace(*cont))
71 ++cont;
72
73 if (!strnicmp(keyword, "URL", 3))
74 _url = DecodeURLString(cont);
75 else if (!strnicmp(keyword, "IconFile", 8))
76 _icon_path = DecodeURLString(cont);
77 }
78 }
79
80 return true;
81 }
82
83 /// convert XBEL bookmark node
84 bool Bookmark::read(const_XMLPos& pos)
85 {
86 _url = pos.get("href").c_str();
87
88 if (pos.go_down("title")) {
89 _name = pos->get_content();
90 pos.back();
91 }
92
93 if (pos.go_down("desc")) {
94 _description = pos->get_content();
95 pos.back();
96 }
97
98 if (pos.go_down("info")) {
99 const_XMLChildrenFilter metadata(pos, "metadata");
100
101 for(const_XMLChildrenFilter::const_iterator it=metadata.begin(); it!=metadata.end(); ++it) {
102 const XMLNode& node = **it;
103 const_XMLPos sub_pos(&node);
104
105 if (node.get("owner") == "ros-explorer") {
106 if (sub_pos.go_down("icon")) {
107 _icon_path = sub_pos.get("path").c_str();
108 _icon_idx = XS_toi(sub_pos.get("index"));
109
110 sub_pos.back(); // </icon>
111 }
112 }
113 }
114
115 pos.back(); // </metadata>
116 pos.back(); // </info>
117 }
118
119 return !_url.empty(); // _url is mandatory.
120 }
121
122 /// write XBEL bookmark node
123 void Bookmark::write(XMLPos& pos) const
124 {
125 pos.create("bookmark");
126
127 pos["href"] = _url.c_str();
128
129 if (!_name.empty()) {
130 pos.create("title");
131 pos->set_content(_name);
132 pos.back();
133 }
134
135 if (!_description.empty()) {
136 pos.create("desc");
137 pos->set_content(_description);
138 pos.back();
139 }
140
141 if (!_icon_path.empty()) {
142 pos.create("info");
143 pos.create("metadata");
144 pos["owner"] = "ros-explorer";
145 pos.create("icon");
146 pos["path"] = _icon_path.c_str();
147 pos["index"].printf(XS_TEXT("%d"), _icon_idx);
148 pos.back(); // </icon>
149 pos.back(); // </metadata>
150 pos.back(); // </info>
151 }
152
153 pos.back();
154 }
155
156
157 /// read bookmark folder from XBEL formated XML tree
158 void BookmarkFolder::read(const_XMLPos& pos)
159 {
160 if (pos.go_down("title")) {
161 _name = pos->get_content();
162 pos.back();
163 }
164
165 if (pos.go_down("desc")) {
166 _description = pos->get_content();
167 pos.back();
168 }
169
170 _bookmarks.read(pos);
171 }
172
173 /// write bookmark folder content from XBEL formated XML tree
174 void BookmarkFolder::write(XMLPos& pos) const
175 {
176 pos.create("folder");
177
178 if (!_name.empty()) {
179 pos.create("title");
180 pos->set_content(_name);
181 pos.back();
182 }
183
184 if (!_description.empty()) {
185 pos.create("desc");
186 pos->set_content(_description);
187 pos.back();
188 }
189
190 _bookmarks.write(pos);
191 }
192
193
194 BookmarkNode::BookmarkNode()
195 : _type(BMNT_NONE)
196 {
197 _pbookmark = NULL;
198 }
199
200 BookmarkNode::BookmarkNode(const Bookmark& bm)
201 : _type(BMNT_BOOKMARK)
202 {
203 _pbookmark = new Bookmark(bm);
204 }
205
206 BookmarkNode::BookmarkNode(const BookmarkFolder& bmf)
207 : _type(BMNT_FOLDER)
208 {
209 _pfolder = new BookmarkFolder(bmf);
210 }
211
212 BookmarkNode::BookmarkNode(const BookmarkNode& other)
213 : _type(other._type)
214 {
215 if (other._type == BMNT_BOOKMARK)
216 _pbookmark = new Bookmark(*other._pbookmark);
217 else if (other._type == BMNT_FOLDER)
218 _pfolder = new BookmarkFolder(*other._pfolder);
219 else
220 _pbookmark = NULL;
221 }
222
223 BookmarkNode::~BookmarkNode()
224 {
225 if (_type == BMNT_BOOKMARK)
226 delete _pbookmark;
227 else if (_type == BMNT_FOLDER)
228 delete _pfolder;
229 }
230
231 BookmarkNode& BookmarkNode::operator=(const Bookmark& bm)
232 {
233 clear();
234
235 _pbookmark = new Bookmark(bm);
236
237 return *this;
238 }
239
240 BookmarkNode& BookmarkNode::operator=(const BookmarkFolder& bmf)
241 {
242 clear();
243
244 _pfolder = new BookmarkFolder(bmf);
245
246 return *this;
247 }
248
249 BookmarkNode& BookmarkNode::operator=(const BookmarkNode& other)
250 {
251 clear();
252
253 _type = other._type;
254
255 if (other._type == BMNT_BOOKMARK)
256 _pbookmark = new Bookmark(*other._pbookmark);
257 else if (other._type == BMNT_FOLDER)
258 _pfolder = new BookmarkFolder(*other._pfolder);
259
260 return *this;
261 }
262
263 void BookmarkNode::clear()
264 {
265 if (_type == BMNT_BOOKMARK) {
266 delete _pbookmark;
267 _pbookmark = NULL;
268 }
269 else if (_type == BMNT_FOLDER) {
270 delete _pfolder;
271 _pfolder = NULL;
272 }
273
274 _type = BMNT_NONE;
275 }
276
277
278 /// read bookmark list from XBEL formated XML tree
279 void BookmarkList::read(const_XMLPos& pos)
280 {
281 const XMLNode::Children& children = pos->get_children();
282
283 for(XMLNode::Children::const_iterator it=children.begin(); it!=children.end(); ++it) {
284 const XMLNode& node = **it;
285 const_XMLPos sub_pos(&node);
286
287 if (node == "folder") {
288 BookmarkFolder folder;
289
290 folder.read(sub_pos);
291
292 push_back(folder);
293 } else if (node == "bookmark") {
294 Bookmark bookmark;
295
296 if (bookmark.read(sub_pos))
297 push_back(bookmark);
298 }
299 }
300 }
301
302 /// write bookmark list into XBEL formated XML tree
303 void BookmarkList::write(XMLPos& pos) const
304 {
305 for(const_iterator it=begin(); it!=end(); ++it) {
306 const BookmarkNode& node = *it;
307
308 if (node._type == BookmarkNode::BMNT_FOLDER) {
309 const BookmarkFolder& folder = *node._pfolder;
310
311 folder.write(pos);
312
313 pos.back();
314 } else if (node._type == BookmarkNode::BMNT_BOOKMARK) {
315 const Bookmark& bookmark = *node._pbookmark;
316
317 if (!bookmark._url.empty())
318 bookmark.write(pos);
319 }
320 }
321 }
322
323
324 /// fill treeview control with bookmark tree content
325 void BookmarkList::fill_tree(HWND hwnd, HTREEITEM parent, HIMAGELIST himagelist, HDC hdc_wnd) const
326 {
327 TV_INSERTSTRUCT tvi;
328
329 tvi.hParent = parent;
330 tvi.hInsertAfter = TVI_LAST;
331
332 TV_ITEM& tv = tvi.item;
333 tv.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM;
334
335 for(const_iterator it=begin(); it!=end(); ++it) {
336 const BookmarkNode& node = *it;
337
338 tv.lParam = (LPARAM)&node;
339
340 if (node._type == BookmarkNode::BMNT_FOLDER) {
341 const BookmarkFolder& folder = *node._pfolder;
342
343 tv.pszText = (LPTSTR)folder._name.c_str();
344 tv.iImage = 3; // folder
345 tv.iSelectedImage = 4; // open folder
346 HTREEITEM hitem = TreeView_InsertItem(hwnd, &tvi);
347
348 folder._bookmarks.fill_tree(hwnd, hitem, himagelist, hdc_wnd);
349 } else if (node._type == BookmarkNode::BMNT_BOOKMARK) {
350 const Bookmark& bookmark = *node._pbookmark;
351
352 tv.pszText = (LPTSTR)bookmark._name.c_str();
353 tv.iImage = 1; // bookmark
354 tv.iSelectedImage = 2; // selected bookmark
355
356 if (!bookmark._icon_path.empty()) {
357 const Icon& icon = g_icon_cache.extract(bookmark._icon_path, bookmark._icon_idx);
358
359 if ((ICON_ID)icon != ICID_NONE)
360 tv.iImage = tv.iSelectedImage = icon.add_to_imagelist(himagelist, hdc_wnd);
361 }
362
363 (void)TreeView_InsertItem(hwnd, &tvi);
364 }
365 }
366 }
367
368
369 /*@@
370
371 /// import Internet Explorer bookmarks from Favorites folder into bookmark list
372 void BookmarkList::import_IE_favorites(ShellDirectory& dir, HWND hwnd)
373 {
374 TCHAR path[MAX_PATH], ext[_MAX_EXT];
375
376 dir.smart_scan(SORT_NAME, SCAN_FILESYSTEM);
377
378 for(Entry*entry=dir._down; entry; entry=entry->_next) {
379 if (entry->_shell_attribs & SFGAO_HIDDEN) // ignore files like "desktop.ini"
380 continue;
381
382 String name;
383
384 if (entry->_etype == ET_SHELL)
385 name = dir._folder.get_name(static_cast<ShellEntry*>(entry)->_pidl);
386 else
387 name = entry->_display_name;
388
389 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
390 BookmarkFolder new_folder;
391
392 new_folder._name = DecodeXMLString(name);
393
394 if (entry->_etype == ET_SHELL) {
395 ShellDirectory new_dir(dir._folder, static_cast<ShellEntry*>(entry)->_pidl, hwnd);
396 new_folder._bookmarks.import_IE_favorites(new_dir, hwnd);
397 } else {
398 entry->get_path(path);
399 ShellDirectory new_dir(GetDesktopFolder(), path, hwnd);
400 new_folder._bookmarks.import_IE_favorites(new_dir, hwnd);
401 }
402
403 push_back(new_folder);
404 } else {
405 Bookmark bookmark;
406
407 bookmark._name = DecodeXMLString(name);
408
409 entry->get_path(path);
410 _tsplitpath(path, NULL, NULL, NULL, ext);
411
412 if (!_tcsicmp(ext, TEXT(".url"))) {
413 bookmark.read_url(path);
414 push_back(bookmark);
415 } else {
416 ///@todo read shell links
417 //assert(0);
418 }
419 }
420 }
421 }
422
423 */
424
425
426 /// read XBEL bookmark file
427 bool Favorites::read(LPCTSTR path)
428 {
429 XMLDoc xbel;
430
431 if (!xbel.read(path))
432 if (xbel._last_error == XML_ERROR_NO_ELEMENTS)
433 return false;
434 else
435 MessageBox(0/*@@g_Globals._hwndDesktop*/, String(xbel._last_error_msg.c_str()),
436 TEXT("ROS Explorer - reading bookmark file"), MB_OK);
437
438 const_XMLPos pos(&xbel);
439
440 if (!pos.go_down("xbel"))
441 return false;
442
443 super::read(pos);
444
445 pos.back();
446
447 return true;
448 }
449
450 /// write XBEL bookmark file
451 void Favorites::write(LPCTSTR path) const
452 {
453 XMLDoc xbel;
454
455 XMLPos pos(&xbel);
456 pos.create("xbel");
457 super::write(pos);
458 pos.back();
459
460 xbel._header._doctype = "<!DOCTYPE xbel"
461 " PUBLIC \"+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML\"\n"
462 " \"http://www.python.org/topics/xml/dtds/xbel-1.0.dtd\">";
463
464 xbel.write(path);
465 }
466
467
468 /*@@
469
470 /// import Internet Explorer bookmarks from Favorites folder
471 bool Favorites::import_IE_favorites(HWND hwnd)
472 {
473 WaitCursor wait;
474
475 StartMenuShellDirs dirs;
476
477 try {
478 dirs.push_back(ShellDirectory(GetDesktopFolder(), SpecialFolderPath(CSIDL_COMMON_FAVORITES, hwnd), hwnd));
479 dirs.push_back(ShellDirectory(GetDesktopFolder(), SpecialFolderPath(CSIDL_FAVORITES, hwnd), hwnd));
480 } catch(COMException&) {
481 }
482
483 for(StartMenuShellDirs::iterator it=dirs.begin(); it!=dirs.end(); ++it) {
484 StartMenuDirectory& smd = *it;
485 ShellDirectory& dir = smd._dir;
486
487 try {
488 super::import_IE_favorites(dir, hwnd);
489 } catch(COMException&) {
490 }
491 }
492
493 return true;
494 }
495
496 */