2
/* Ekiga -- A VoIP and Video-Conferencing application
3
* Copyright (C) 2000-2009 Damien Sandras <dsandras@seconix.com>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20
* Ekiga is licensed under the GPL license and as a special exception,
21
* you have permission to link or otherwise combine this program with the
22
* programs OPAL, OpenH323 and PWLIB, and distribute the combination,
23
* without applying the requirements of the GNU GPL to the OPAL, OpenH323
24
* and PWLIB programs, as long as you do follow the requirements of the
25
* GNU GPL for all the rest of the software thus combined.
30
* rl-heap.cpp - description
31
* ------------------------------------------
32
* begin : written in 2008 by Julien Puydt
33
* copyright : (c) 2008 by Julien Puydt
34
* description : resource-list heap implementation
38
#include <glib/gi18n.h>
42
#include "robust-xml.h"
43
#include "form-request-simple.h"
44
#include "xcap-core.h"
48
RL::Heap::Heap (Ekiga::ServiceCore& services_,
51
node(node_), name(NULL),
52
root(NULL), user(NULL),
53
username(NULL), password(NULL),
54
doc(NULL), list_node(NULL)
57
xmlChar* xml_str = NULL;
59
xml_str = xmlGetProp (node, BAD_CAST "writable");
63
xmlSetProp (node, BAD_CAST "writable", BAD_CAST "0");
67
for (xmlNodePtr child = node->children; child != NULL; child = child->next) {
69
if (child->type == XML_ELEMENT_NODE
70
&& child->name != NULL) {
72
if (xmlStrEqual (BAD_CAST ("name"), child->name)) {
77
if (xmlStrEqual (BAD_CAST ("root"), child->name)) {
82
if (xmlStrEqual (BAD_CAST ("user"), child->name)) {
87
if (xmlStrEqual (BAD_CAST ("username"), child->name)) {
92
if (xmlStrEqual (BAD_CAST ("password"), child->name)) {
101
name = xmlNewChild (node, NULL, BAD_CAST "name",
102
BAD_CAST robust_xmlEscape(node->doc,
103
_("Unnamed")).c_str ());
105
root = xmlNewChild (node, NULL, BAD_CAST "root", BAD_CAST "");
107
user = xmlNewChild (node, NULL, BAD_CAST "user", BAD_CAST "");
108
if (username == NULL)
109
username = xmlNewChild (node, NULL, BAD_CAST "username", BAD_CAST "");
110
if (password == NULL)
111
password = xmlNewChild (node, NULL, BAD_CAST "password", BAD_CAST "");
116
RL::Heap::Heap (Ekiga::ServiceCore& services_,
117
const std::string name_,
118
const std::string root_,
119
const std::string user_,
120
const std::string username_,
121
const std::string password_,
124
node(NULL), name(NULL),
125
root(NULL), user(NULL),
126
username(NULL), password(NULL),
127
doc(NULL), list_node(NULL)
129
node = xmlNewNode (NULL, BAD_CAST "entry");
131
xmlSetProp (node, BAD_CAST "writable", BAD_CAST "1");
133
xmlSetProp (node, BAD_CAST "writable", BAD_CAST "0");
135
if ( !name_.empty ())
136
name = xmlNewChild (node, NULL,
138
BAD_CAST robust_xmlEscape (node->doc,
141
name = xmlNewChild (node, NULL,
143
BAD_CAST robust_xmlEscape (node->doc,
144
_("Unnamed")).c_str ());
145
root = xmlNewChild (node, NULL,
147
BAD_CAST robust_xmlEscape (node->doc,
149
user = xmlNewChild (node, NULL,
151
BAD_CAST robust_xmlEscape (node->doc,
153
username = xmlNewChild (node, NULL,
155
BAD_CAST robust_xmlEscape (node->doc,
156
username_).c_str ());
157
password = xmlNewChild (node, NULL,
159
BAD_CAST robust_xmlEscape (node->doc,
160
password_).c_str ());
171
RL::Heap::get_name () const
174
xmlChar* str = xmlNodeGetContent (name);
176
result = (const char*)str;
178
result = _("Unnamed");
186
RL::Heap::visit_presentities (sigc::slot1<bool, gmref_ptr<Ekiga::Presentity> > visitor)
190
for (std::map<gmref_ptr<Presentity>,std::list<sigc::connection> >::iterator
191
iter = presentities.begin ();
192
go_on && iter != presentities.end ();
194
go_on = visitor (iter->first);
198
RL::Heap::populate_menu (Ekiga::MenuBuilder& builder)
200
builder.add_action ("add", _("_Add a new contact"),
201
sigc::mem_fun (this, &RL::Heap::new_entry));
202
builder.add_action ("refresh", _("_Refresh contact list"),
203
sigc::mem_fun (this, &RL::Heap::refresh));
204
builder.add_action ("properties", _("Contact list _properties"),
205
sigc::mem_fun (this, &RL::Heap::edit));
210
RL::Heap::populate_menu_for_group (std::string /*group*/,
211
Ekiga::MenuBuilder& /*builder*/)
213
return false; // FIXME
217
RL::Heap::get_node () const
225
gmref_ptr<XCAP::Core> xcap(services.get ("xcap-core"));
226
std::string root_str;
227
std::string username_str;
228
std::string password_str;
229
std::string user_str;
232
xmlChar* str = xmlNodeGetContent (root);
234
root_str = (const char*)str;
237
xmlChar* str = xmlNodeGetContent (user);
239
user_str = (const char*)str;
242
xmlChar* str = xmlNodeGetContent (username);
244
username_str = (const char*)str;
247
xmlChar* str = xmlNodeGetContent (password);
249
password_str = (const char*)str;
251
gmref_ptr<XCAP::Path> path(new XCAP::Path (root_str, "resource-lists",
253
path->set_credentials (username_str, password_str);
254
path = path->build_child ("resource-lists");
256
while (presentities.begin () != presentities.end ()) {
258
presentities.begin()->first->removed.emit ();
259
for (std::list<sigc::connection>::iterator iter2
260
= presentities.begin()->second.begin ();
261
iter2 != presentities.begin()->second.end ();
263
iter2->disconnect ();
264
presentities.erase (presentities.begin()->first);
271
xcap->read (path, sigc::mem_fun (this, &RL::Heap::on_document_received));
275
RL::Heap::on_document_received (bool error,
280
// FIXME: do something
281
std::cout << "XCAP error: " << value << std::endl;
289
RL::Heap::parse_doc (std::string raw)
291
doc = xmlRecoverMemory (raw.c_str (), raw.length ());
293
xmlNodePtr doc_root = xmlDocGetRootElement (doc);
296
|| doc_root->name == NULL
297
|| !xmlStrEqual (BAD_CAST "resource-lists", doc_root->name)) {
299
std::cout << "Invalid document in " << __PRETTY_FUNCTION__ << std::endl;
300
// FIXME: warn the user somehow?
306
for (xmlNodePtr child = doc_root->children;
309
if (child->type == XML_ELEMENT_NODE
310
&& child->name != NULL
311
&& xmlStrEqual (BAD_CAST ("list"), child->name)) {
314
break; // read only one!
320
RL::Heap::parse_list (xmlNodePtr list)
322
std::string root_str;
323
std::string user_str;
324
std::string username_str;
325
std::string password_str;
326
bool writable = false;
330
xmlChar* str = xmlNodeGetContent (root);
332
root_str = (const char*)str;
335
xmlChar* str = xmlNodeGetContent (user);
337
user_str = (const char*)str;
340
xmlChar* str = xmlNodeGetContent (username);
342
username_str = (const char*)str;
345
xmlChar* str = xmlNodeGetContent (password);
347
password_str = (const char*)str;
350
xmlChar* str = xmlGetProp (node, BAD_CAST "writable");
353
if (xmlStrEqual (str, BAD_CAST "1"))
359
gmref_ptr<XCAP::Path> path(new XCAP::Path (root_str, "resource-lists",
361
path->set_credentials (username_str, password_str);
362
path = path->build_child ("resource-lists");
363
path = path->build_child ("list");
365
for (xmlNodePtr child = list->children;
368
if (child->type == XML_ELEMENT_NODE
369
&& child->name != NULL
370
&& xmlStrEqual (BAD_CAST ("entry"), child->name)) {
372
gmref_ptr<Presentity> presentity(new Presentity (services, path, child, writable));
373
std::list<sigc::connection> conns;
374
conns.push_back (presentity->updated.connect (sigc::bind (presentity_updated.make_slot (),presentity)));
375
conns.push_back (presentity->removed.connect (sigc::bind(presentity_removed.make_slot (),presentity)));
376
conns.push_back (presentity->trigger_reload.connect (sigc::mem_fun (this, &RL::Heap::refresh)));
377
conns.push_back (presentity->questions.connect (questions.make_slot()));
378
presentities[presentity]=conns;
379
presentity_added.emit (presentity);
385
RL::Heap::push_presence (const std::string uri_,
386
const std::string presence)
388
for (std::map<gmref_ptr<Presentity>,std::list<sigc::connection> >::iterator
389
iter = presentities.begin ();
390
iter != presentities.end ();
393
if (iter->first->get_uri () == uri_)
394
iter->first->set_presence (presence);
399
RL::Heap::push_status (const std::string uri_,
400
const std::string status)
402
for (std::map<gmref_ptr<Presentity>,std::list<sigc::connection> >::iterator
403
iter = presentities.begin ();
404
iter != presentities.end ();
407
if (iter->first->get_uri () == uri_)
408
iter->first->set_status (status);
415
Ekiga::FormRequestSimple request(sigc::mem_fun (this,
416
&RL::Heap::on_edit_form_submitted));
418
std::string name_str;
419
std::string root_str;
420
std::string username_str;
421
std::string password_str;
422
std::string user_str;
423
bool writable = false;
426
xmlChar* str = xmlNodeGetContent (root);
429
root_str = (const char*)str;
434
xmlChar* str = xmlNodeGetContent (user);
437
user_str = (const char*)str;
442
xmlChar* str = xmlNodeGetContent (username);
445
username_str = (const char*)str;
450
xmlChar* str = xmlNodeGetContent (password);
453
password_str = (const char*)str;
458
xmlChar* str = xmlGetProp (node, BAD_CAST "writable");
461
if (xmlStrEqual (str, BAD_CAST "1"))
467
request.title (_("Edit contact list properties"));
469
request.instructions (_("Please edit the following fields (no identifier"
472
request.text ("name", _("Contact list's name"), get_name ());
473
/* "Document" used as a name -- uri point to the root of a document tree */
474
request.text ("root", _("Document root"), root_str);
475
request.text ("user", _("Identifier"), user_str);
476
request.boolean ("writable", _("Writable"), writable);
477
request.text ("username", _("Server username"), username_str);
478
request.private_text ("password", _("Server password"), password_str);
480
if (!questions.handle_request (&request)) {
482
// FIXME: better error reporting
484
std::cout << "Unhandled form request in "
485
<< __PRETTY_FUNCTION__ << std::endl;
491
RL::Heap::on_edit_form_submitted (bool submitted,
499
std::string name_str = result.text ("name");
500
std::string root_str = result.text ("root");
501
std::string user_str = result.text ("user");
502
std::string username_str = result.text ("username");
503
std::string password_str = result.private_text ("password");
504
bool writable = result.boolean ("writable");
507
xmlSetProp (node, BAD_CAST "writable", BAD_CAST "1");
509
xmlSetProp (node, BAD_CAST "writable", BAD_CAST "0");
510
robust_xmlNodeSetContent (node, &name, "name", name_str);
511
robust_xmlNodeSetContent (node, &root, "root", root_str);
512
robust_xmlNodeSetContent (node, &user, "user", user_str);
513
robust_xmlNodeSetContent (node, &username, "username", username_str);
514
robust_xmlNodeSetContent (node, &password, "password", password_str);
516
trigger_saving.emit ();
519
} catch (Ekiga::Form::not_found) {
521
std::cerr << "Invalid result form" << std::endl; // FIXME: do better
526
RL::Heap::new_entry ()
528
Ekiga::FormRequestSimple request(sigc::mem_fun (this, &RL::Heap::on_new_entry_form_submitted));
530
request.title (_("Add a remote contact"));
531
request.instructions (_("Please fill in this form to create a new "
532
"contact on a remote server"));
534
std::set<std::string> all_groups;
535
for (std::map<gmref_ptr<Presentity>,std::list<sigc::connection> >::iterator
536
iter = presentities.begin ();
537
iter != presentities.end ();
540
std::set<std::string> groups = iter->first->get_groups ();
541
all_groups.insert (groups.begin (), groups.end ());
544
request.text ("name", _("Name:"), "");
545
request.text ("uri", _("Address:"), "");
546
request.editable_set ("groups", _("Choose groups:"),
547
std::set<std::string>(), all_groups);
549
if (!questions.handle_request (&request)) {
551
// FIXME: better error reporting
553
std::cout << "Unhandled form request in "
554
<< __PRETTY_FUNCTION__ << std::endl;
560
RL::Heap::on_new_entry_form_submitted (bool submitted,
568
std::string entry_name = result.text ("name");
569
std::string entry_uri = result.text ("uri");
570
std::set<std::string> entry_groups = result.editable_set ("groups");
572
xmlNodePtr entry_node = xmlNewChild (list_node, NULL,
573
BAD_CAST "entry", NULL);
574
xmlSetProp (entry_node, BAD_CAST "uri",
575
BAD_CAST robust_xmlEscape (doc, entry_uri).c_str ());
576
xmlNewChild (entry_node, NULL, BAD_CAST "display-name",
577
BAD_CAST robust_xmlEscape (doc, entry_name).c_str ());
578
xmlNsPtr ns = xmlSearchNsByHref (doc, entry_node,
579
BAD_CAST "http://www.ekiga.org");
582
// FIXME: we should handle the case, even if it shouldn't happen
585
for (std::set<std::string>::const_iterator iter = entry_groups.begin ();
586
iter != entry_groups.end ();
589
xmlNewChild (entry_node, ns, BAD_CAST "group",
590
BAD_CAST robust_xmlEscape (doc, *iter).c_str ());
593
xmlBufferPtr buffer = xmlBufferCreate ();
594
int res = xmlNodeDump (buffer, doc, entry_node, 0, 0);
598
std::string root_str;
599
std::string username_str;
600
std::string password_str;
601
std::string user_str;
604
xmlChar* str = xmlNodeGetContent (root);
606
root_str = (const char*)str;
609
xmlChar* str = xmlNodeGetContent (user);
611
user_str = (const char*)str;
614
xmlChar* str = xmlNodeGetContent (username);
616
username_str = (const char*)str;
619
xmlChar* str = xmlNodeGetContent (password);
621
password_str = (const char*)str;
623
gmref_ptr<XCAP::Path> path(new XCAP::Path (root_str, "resource-lists",
625
path->set_credentials (username_str, password_str);
626
path = path->build_child ("resource-lists");
627
path = path->build_child ("list");
628
path = path->build_child_with_attribute ("entry", "uri", entry_uri);
629
gmref_ptr<XCAP::Core> xcap(services.get ("xcap-core"));
630
xcap->write (path, "application/xcap-el+xml",
631
(const char*)xmlBufferContent (buffer),
633
&RL::Heap::new_entry_result));
635
xmlBufferFree (buffer);
636
} catch (Ekiga::Form::not_found exc) {
638
std::cerr << "Invalid result form" << std::endl; // FIXME: do better
643
RL::Heap::new_entry_result (std::string error)
645
if ( !error.empty ()) {
647
std::cout << "XCAP Error: " << error << std::endl;