Exemple #1
0
void
RL::Heap::on_edit_form_submitted (bool submitted,
				  Ekiga::Form& result)
{
  if (!submitted)
    return;

  std::string name_str = result.text ("name");
  std::string root_str = result.text ("root");
  std::string user_str = result.text ("user");
  std::string username_str = result.text ("username");
  std::string password_str = result.private_text ("password");
  bool writable = result.boolean ("writable");

  if (writable)
    xmlSetProp (node, BAD_CAST "writable", BAD_CAST "1");
  else
    xmlSetProp (node, BAD_CAST "writable", BAD_CAST "0");
  robust_xmlNodeSetContent (node, &name, "name", name_str);
  robust_xmlNodeSetContent (node, &root, "root", root_str);
  robust_xmlNodeSetContent (node, &user, "user", user_str);
  robust_xmlNodeSetContent (node, &username, "username", username_str);
  robust_xmlNodeSetContent (node, &password, "password", password_str);

  trigger_saving.emit ();
  updated.emit ();
  refresh ();
}
void
LM::Account::on_edit_form_submitted (bool submitted,
				     Ekiga::Form &result)
{
  if (!submitted)
    return;

  disable (); // don't stay connected!

  std::string name = result.text ("name");
  std::string user = result.text ("user");
  std::string server = result.text ("server");
  std::string port = result.text ("port");
  std::string resource = result.text ("resource");
  std::string password = result.private_text ("password");
  bool enable_on_startup = result.boolean ("enabled");

  xmlSetProp (node, BAD_CAST "name", BAD_CAST name.c_str ());
  xmlSetProp (node, BAD_CAST "user", BAD_CAST user.c_str ());
  xmlSetProp (node, BAD_CAST "server", BAD_CAST server.c_str ());
  xmlSetProp (node, BAD_CAST "port", BAD_CAST port.c_str ());
  xmlSetProp (node, BAD_CAST "resource", BAD_CAST resource.c_str ());
  xmlSetProp (node, BAD_CAST "password", BAD_CAST password.c_str ());

  if (enable_on_startup) {

    xmlSetProp (node, BAD_CAST "startup", BAD_CAST "true");
    enable ();
  } else {

    xmlSetProp (node, BAD_CAST "startup", BAD_CAST "false");
    updated ();
  }
}
void
RL::Presentity::edit_presentity_form_submitted (bool submitted,
        Ekiga::Form &result)
{
    if (!submitted)
        return;

    const std::string new_name = result.text ("name");
    const std::string new_uri = result.text ("uri");
    const std::set<std::string> new_groups = result.editable_set ("groups");
    std::map<std::string, xmlNodePtr> future_group_nodes;
    xmlNsPtr ns = xmlSearchNsByHref (node->doc, node,
                                     BAD_CAST "http://www.ekiga.org");
    bool reload = false;

    robust_xmlNodeSetContent (node, &name_node, "name", new_name);

    if (uri != new_uri) {

        xmlSetProp (node, (const xmlChar*)"uri", (const xmlChar*)uri.c_str ());
        boost::shared_ptr<Ekiga::PresenceCore> presence_core(services.get<Ekiga::PresenceCore> ("presence-core"));
        presence_core->unfetch_presence (uri);
        reload = true;
    }

    for (std::map<std::string, xmlNodePtr>::const_iterator iter
            = group_nodes.begin ();
            iter != group_nodes.end () ;
            iter++) {

        if (new_groups.find (iter->first) == new_groups.end ()) {

            xmlUnlinkNode (iter->second);
            xmlFreeNode (iter->second);
        }
        else {
            future_group_nodes[iter->first] = iter->second;
        }
    }

    for (std::set<std::string>::const_iterator iter = new_groups.begin ();
            iter != new_groups.end ();
            iter++) {

        if (std::find (groups.begin (), groups.end (), *iter) == groups.end ())
            future_group_nodes[*iter] = xmlNewChild (node, ns,
                                        BAD_CAST "group",
                                        BAD_CAST robust_xmlEscape (node->doc, *iter).c_str ());
    }

    group_nodes = future_group_nodes;
    groups = new_groups;

    save (reload);
}
void Opal::Bank::on_new_account_form_submitted (Ekiga::Form &result,
                                                Account::Type t)
{
  try {

    Ekiga::FormRequestSimple request;

    std::string error;
    std::string new_name = (t == Opal::Account::SIP || t == Opal::Account::H323) ? result.text ("name") : result.hidden ("name");
    std::string new_host = (t == Opal::Account::SIP || t == Opal::Account::H323) ? result.text ("host") : result.hidden ("host");
    std::string new_user = result.text ("user");
    std::string new_authentication_user = (t == Opal::Account::SIP) ? result.text ("authentication_user") : new_user;
    std::string new_password = result.private_text ("password");
    bool new_enabled = result.boolean ("enabled");
    unsigned new_timeout = atoi ((t == Opal::Account::SIP || t == Opal::Account::H323) ? 
                                 result.text ("timeout").c_str () : result.hidden ("timeout").c_str ());

    result.visit (request);

    if (new_name.empty ()) 
      error = _("You did not supply a name for that account.");
    else if (new_host.empty ()) 
      error = _("You did not supply a host to register to.");
    else if (new_user.empty ())
      error = _("You did not supply a user name for that account.");
    else if (new_timeout < 10)
      error = _("The timeout should have a bigger value.");

    if (!error.empty ()) {
      request.error (error);
      request.submitted.connect (sigc::bind (sigc::mem_fun (this, &Opal::Bank::on_new_account_form_submitted) ,t));

      if (!questions.handle_request (&request)) {
#ifdef __GNUC__
        std::cout << "Unhandled form request in "
          << __PRETTY_FUNCTION__ << std::endl;
#endif
      }
    }
    else {

      add (t, new_name, new_host, new_user, new_authentication_user, new_password, new_enabled, new_timeout);
      save ();
    }

  } catch (Ekiga::Form::not_found) {

    std::cerr << "Invalid result form" << std::endl;
  }
}
void
LM::Presentity::edit_presentity_form_submitted (bool submitted,
						Ekiga::Form& result)
{
  if (!submitted)
    return;

  const std::string name = result.text ("name");
  const std::set<std::string> groups = result.editable_set ("groups");
  LmMessage* message = lm_message_new_with_sub_type (NULL, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET);
  LmMessageNode* query = lm_message_node_add_child (lm_message_get_node (message), "query", NULL);
  lm_message_node_set_attribute (query, "xmlns", "jabber:iq:roster");
  LmMessageNode* node = lm_message_node_add_child (query, "item", NULL);

  {
    gchar* escaped = g_markup_escape_text (name.c_str (), -1);
    lm_message_node_set_attributes (node,
				    "jid", get_jid ().c_str (),
				    "name", escaped,
				    NULL);
    g_free (escaped);
  }

  for (std::set<std::string>::const_iterator iter = groups.begin (); iter != groups.end (); ++iter) {

    gchar* escaped = g_markup_escape_text (iter->c_str (), -1);
    lm_message_node_add_child (node, "group", escaped);
    g_free (escaped);
  }

  lm_connection_send_with_reply (connection, message,
				 build_message_handler (boost::bind(&LM::Presentity::handle_edit_reply, this, _1, _2)), NULL);
  lm_message_unref (message);
}
Exemple #6
0
void
Local::Heap::new_presentity_form_submitted (bool submitted,
					    Ekiga::Form &result)
{
  if (!submitted)
    return;

  gmref_ptr<Ekiga::PresenceCore> presence_core = core.get ("presence-core");
  const std::string name = result.text ("name");
  const std::string good_uri = result.hidden ("good-uri");
  std::string uri;
  const std::set<std::string> groups = result.editable_set ("groups");

  if (good_uri == "yes")
    uri = result.hidden ("uri");
  else
    uri = result.text ("uri");

  size_t pos = uri.find_first_of (' ');
  if (pos != std::string::npos)
    uri = uri.substr (0, pos);
  if (presence_core->is_supported_uri (uri)
      && !has_presentity_with_uri (uri)) {

    add (name, uri, groups);
    save ();
  } else {

    Ekiga::FormRequestSimple request(sigc::mem_fun (this, &Local::Heap::new_presentity_form_submitted));

    result.visit (request);
    if (!presence_core->is_supported_uri (uri))
      request.error (_("You supplied an unsupported address"));
    else
      request.error (_("You already have a contact with this address!"));

    if (!questions.handle_request (&request)) {

      // FIXME: better error handling
#ifdef __GNUC__
      std::cout << "Unhandled form request in "
		<< __PRETTY_FUNCTION__ << std::endl;
#endif
    }
  }
}
Exemple #7
0
void Opal::Bank::on_new_account_form_submitted (bool submitted,
						Ekiga::Form &result,
                                                Account::Type acc_type)
{
  if (!submitted)
    return;

  boost::shared_ptr<Ekiga::FormRequestSimple> request = boost::shared_ptr<Ekiga::FormRequestSimple> (new Ekiga::FormRequestSimple (boost::bind (&Opal::Bank::on_new_account_form_submitted, this, _1, _2, acc_type)));

  std::string error;
  std::string new_name = (acc_type == Opal::Account::SIP
			  || acc_type == Opal::Account::H323) ? result.text ("name") : result.hidden ("name");
  std::string new_host = (acc_type == Opal::Account::SIP
			  || acc_type == Opal::Account::H323) ? result.text ("host") : result.hidden ("host");
  std::string new_user = result.text ("user");
  std::string new_authentication_user = (acc_type == Opal::Account::SIP) ? result.text ("authentication_user") : new_user;
  std::string new_password = result.private_text ("password");
  bool new_enabled = result.boolean ("enabled");
  unsigned new_timeout = atoi ((acc_type == Opal::Account::SIP
				|| acc_type == Opal::Account::H323) ?
			       result.text ("timeout").c_str () : result.hidden ("timeout").c_str ());

  result.visit (*request);

  if (new_name.empty ())
    error = _("You did not supply a name for that account.");
  else if (new_host.empty ())
    error = _("You did not supply a host to register to.");
  else if (new_user.empty ())
    error = _("You did not supply a user name for that account.");
  else if (new_timeout < 10)
    error = _("The timeout should be at least 10 seconds.");

  if (!error.empty ()) {
    request->error (error);

    questions (request);
  }
  else {

    add (acc_type, new_name, new_host, new_user, new_authentication_user,
	 new_password, new_enabled, new_timeout);
    save ();
  }
}
Exemple #8
0
bool
RL::Cluster::on_new_heap_form_submitted (bool submitted,
					 Ekiga::Form &result,
                                         std::string &/*error*/)
{
  if (!submitted)
    return false;

  const std::string name = result.text ("name");
  const std::string uri = result.text ("uri");
  const std::string username = result.text ("username");
  const std::string password = result.text ("password");
  const std::string user = result.text ("user");
  bool writable = result.boolean ("writable");

  add (name, uri, username, password, user, writable);

  return true;
}
Exemple #9
0
void
Local::Heap::new_presentity_form_submitted (bool submitted,
					    Ekiga::Form &result)
{
  if (!submitted)
    return;

  boost::shared_ptr<Ekiga::PresenceCore> pcore = presence_core.lock ();
  if (!pcore)
    return;

  const std::string name = result.text ("name");
  const std::string good_uri = result.hidden ("good-uri");
  std::string uri;
  const std::set<std::string> groups = result.editable_set ("groups");

  if (good_uri == "yes")
    uri = result.hidden ("uri");
  else
    uri = result.text ("uri");

  uri = canonize_uri (uri);

  if (pcore->is_supported_uri (uri)
      && !has_presentity_with_uri (uri)) {

    add (name, uri, groups);
    save ();
  } else {

    boost::shared_ptr<Ekiga::FormRequestSimple> request = boost::shared_ptr<Ekiga::FormRequestSimple>(new Ekiga::FormRequestSimple (boost::bind (&Local::Heap::new_presentity_form_submitted, this, _1, _2)));

    result.visit (*request);
    if (!pcore->is_supported_uri (uri))
      request->error (_("You supplied an unsupported address"));
    else
      request->error (_("You already have a contact with this address!"));

    questions (request);
  }
}
Exemple #10
0
void
LM::HeapRoster::add_item_form_submitted (bool submitted,
					 Ekiga::Form& result)
{
  if ( !submitted)
    return;

  const std::string jid = result.text ("jid");
  const std::string contact_name = result.text ("name");
  const std::list<std::string> groups = result.editable_set ("groups");

  if ( !jid.empty ()) {

    LmMessage* message = lm_message_new_with_sub_type (NULL, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET);
    LmMessageNode* query = lm_message_node_add_child (lm_message_get_node (message), "query", NULL);
    lm_message_node_set_attribute (query, "xmlns", "jabber:iq:roster");
    LmMessageNode* node = lm_message_node_add_child (query, "item", NULL);
    lm_message_node_set_attributes (node,
				    "jid", jid.c_str (),
				    NULL);
    if ( !contact_name.empty ()) {

      gchar* escaped = g_markup_escape_text (contact_name.c_str (), -1);
      lm_message_node_set_attributes (node,
				      "name", escaped,
				      NULL);
    }

    for (std::list<std::string>::const_iterator iter = groups.begin (); iter != groups.end (); ++iter) {

      gchar* escaped = g_markup_escape_text (iter->c_str (), -1);
      lm_message_node_add_child (node, "group", escaped);
      g_free (escaped);
    }

    items_added_by_me.insert (jid);
    lm_connection_send (connection, message, NULL);
    lm_message_unref (message);
  }
}
void
OPENLDAP::Source::on_new_book_form_submitted (Ekiga::Form &result)
{
  try {

    std::string name = result.text ("name");
    std::string hostname = result.text ("hostname");
    std::string port_string = result.text ("port");
    std::string base = result.text ("base");
    std::string scope = result.single_choice ("scope");
    std::string call_attribute = result.text ("call-attribute");
    std::string password = result.private_text ("password");
    int port = atoi (port_string.c_str ());

    add (name, hostname, port, base, scope, call_attribute, password);
    save ();

  } catch (Ekiga::Form::not_found) {

    std::cerr << "Invalid result form" << std::endl; // FIXME: do better
  }
}
Exemple #12
0
void
LM::Bank::on_new_account_form_submitted (bool submitted,
					 Ekiga::Form &result)
{
  if (!submitted)
    return;

  std::string name = result.text ("name");
  std::string user = result.text ("user");
  std::string server = result.text ("server");
  std::string resource = result.text ("resource");
  std::string password = result.private_text ("password");
  bool enable_on_startup = result.boolean ("enabled");

  boost::shared_ptr<Account> account (new Account (details, dialect, cluster,
						   name, user, server, LM_CONNECTION_DEFAULT_PORT,
						   resource, password,
						   enable_on_startup));
  xmlNodePtr root = xmlDocGetRootElement (doc);
  xmlAddChild (root, account->get_node ());

  save ();
  add (account);
}
Exemple #13
0
void
Local::Heap::rename_group_form_submitted (std::string old_name,
					  bool submitted,
					  Ekiga::Form& result)
{
  if (!submitted)
    return;

  const std::string new_name = result.text ("name");

  if ( !new_name.empty () && new_name != old_name) {

    rename_group_form_submitted_helper helper (old_name, new_name);
    visit_presentities (sigc::mem_fun (helper, &rename_group_form_submitted_helper::rename_group));
  }
}
Exemple #14
0
bool
Opal::Presentity::edit_presentity_form_submitted (bool submitted,
                                                  Ekiga::Form &result,
                                                  std::string &error)
{
  if (!submitted)
    return false;

  const std::string new_name = result.text ("name");
  const std::list<std::string> groups = get_groups ();
  const std::list<std::string> new_groups = result.editable_list ("groups");
  std::string new_uri = result.text ("uri");
  const std::string uri = get_uri ();
  std::set<xmlNodePtr> nodes_to_remove;

  if (new_name.empty ()) {
    error = _("You did not provide a valid name");
    return false;
  }
  else if (new_uri.empty ()) {
    error = _("You did not provide a valid address");
    return false;
  }

  new_uri = canonize_uri (new_uri);

  for (xmlNodePtr child = node->children ;
       child != NULL ;
       child = child->next) {

    if (child->type == XML_ELEMENT_NODE
        && child->name != NULL)
      if (xmlStrEqual (BAD_CAST ("name"), child->name))
        robust_xmlNodeSetContent (node, &child, "name", new_name);
  }

  if (uri != new_uri) {
    xmlSetProp (node, (const xmlChar*)"uri", (const xmlChar*)new_uri.c_str ());
    account.unfetch (uri);
    account.fetch (new_uri);
    Ekiga::Runtime::run_in_main (boost::bind (&Opal::Account::presence_status_in_main, &account, new_uri, "unknown", ""));
  }

  // the first loop looks at groups we were in: are we still in?
  for (xmlNodePtr child = node->children ;
       child != NULL ;
       child = child->next) {

    if (child->type == XML_ELEMENT_NODE
        && child->name != NULL) {

      if (xmlStrEqual (BAD_CAST ("group"), child->name)) {

        xmlChar* xml_str = xmlNodeGetContent (child);

        if (xml_str != NULL) {
          if (std::find (new_groups.begin (), new_groups.end (), (const char*) xml_str) == new_groups.end ())
            nodes_to_remove.insert (child); // don't free what we loop on!
          xmlFree (xml_str);
        }
      }
    }
  }

  // ok, now we can clean up!
  for (std::set<xmlNodePtr>::iterator iter = nodes_to_remove.begin ();
       iter != nodes_to_remove.end ();
       ++iter) {

    xmlUnlinkNode (*iter);
    xmlFreeNode (*iter);
  }

  // the second loop looks for groups we weren't in but are now
  for (std::list<std::string>::const_iterator iter = new_groups.begin ();
       iter != new_groups.end ();
       iter++) {

    if (std::find (groups.begin (), groups.end (), *iter) == groups.end ())
      xmlNewChild (node, NULL,
                   BAD_CAST "group",
                   BAD_CAST robust_xmlEscape (node->doc, *iter).c_str ());
  }

  updated (this->shared_from_this ());
  trigger_saving ();

  return true;
}
Exemple #15
0
void
RL::Heap::on_new_entry_form_submitted (bool submitted,
				       Ekiga::Form& result)
{
  if (!submitted)
    return;

  std::string entry_name = result.text ("name");
  std::string entry_uri = result.text ("uri");
  std::set<std::string> entry_groups = result.editable_set ("groups");

  xmlNodePtr entry_node = xmlNewChild (list_node, NULL,
				       BAD_CAST "entry", NULL);
  xmlSetProp (entry_node, BAD_CAST "uri",
	      BAD_CAST robust_xmlEscape (doc.get (), entry_uri).c_str ());
  xmlNewChild (entry_node, NULL, BAD_CAST "display-name",
	       BAD_CAST robust_xmlEscape (doc.get (), entry_name).c_str ());
  xmlNsPtr ns = xmlSearchNsByHref (doc.get (), entry_node,
				   BAD_CAST "http://www.ekiga.org");
  if (ns == NULL) {

    // FIXME: we should handle the case, even if it shouldn't happen
  }

  for (std::set<std::string>::const_iterator iter = entry_groups.begin ();
       iter != entry_groups.end ();
       ++iter) {

    xmlNewChild (entry_node, ns, BAD_CAST "group",
		 BAD_CAST robust_xmlEscape (doc.get (), *iter).c_str ());
  }

  xmlBufferPtr buffer = xmlBufferCreate ();
  int res = xmlNodeDump (buffer, doc.get (), entry_node, 0, 0);

  if (res >= 0) {

    std::string root_str;
    std::string username_str;
    std::string password_str;
    std::string user_str;

    {
      xmlChar* str = xmlNodeGetContent (root);
      if (str != NULL)
	root_str = (const char*)str;
    }
    {
      xmlChar* str = xmlNodeGetContent (user);
      if (str != NULL)
	user_str = (const char*)str;
    }
    {
      xmlChar* str = xmlNodeGetContent (username);
      if (str != NULL)
	username_str = (const char*)str;
    }
    {
      xmlChar* str = xmlNodeGetContent (password);
      if (str != NULL)
	password_str = (const char*)str;
    }
    gmref_ptr<XCAP::Path> path(new XCAP::Path (root_str, "resource-lists",
					       user_str));
    path->set_credentials (username_str, password_str);
    path = path->build_child ("resource-lists");
    path = path->build_child ("list");
    path = path->build_child_with_attribute ("entry", "uri", entry_uri);
    gmref_ptr<XCAP::Core> xcap(services.get ("xcap-core"));
    xcap->write (path, "application/xcap-el+xml",
		 (const char*)xmlBufferContent (buffer),
		 sigc::mem_fun (this, &RL::Heap::new_entry_result));
  }
  xmlBufferFree (buffer);
}
Exemple #16
0
int
OPENLDAP::BookFormInfo (Ekiga::Form &result,
			struct BookInfo &bookinfo,
			std::string &errmsg)
{
  LDAPURLDesc *url_base = NULL, *url_host = NULL;
  char *url_str;

  std::string name = result.text ("name");
  std::string uri = result.text ("uri");
  std::string nameAttr = result.text ("nameAttr");
  std::string callAttr = result.text ("callAttr");
  std::string filter = result.text ("filter");

  errmsg = "";

  if (name.empty())
    errmsg += _("Please provide a Book Name for this directory\n");

  if (uri.empty())
    errmsg += _("Please provide a Server URI\n");

  if (nameAttr.empty())
    errmsg += _("Please provide a DisplayName attribute\n");

  if (callAttr.empty())
    errmsg += _("Please provide a Call attribute\n");

  if (ldap_url_parse (uri.c_str(), &url_host))
    errmsg += _("Invalid Server URI\n");

  if (!errmsg.empty()) {
    return -1;
  }

  if (filter.empty())
    filter = "(cn=$)";

  bookinfo.name = name;
  std::string base = result.text ("base");
  std::string new_bits = "ldap:///?" +
    result.text ("nameAttr") + "," +
    result.text ("callAttr") + "?" +
    result.single_choice ("scope") + "?" +
    result.text ("filter");
  bookinfo.authcID = result.text ("authcID");
  bookinfo.password = result.text ("password");
  bookinfo.starttls = result.boolean ("startTLS");
  bookinfo.sasl = result.boolean ("sasl");
  bookinfo.saslMech = result.single_choice ("saslMech");

  if (bookinfo.sasl || bookinfo.starttls) {
    new_bits += "?";
    if (bookinfo.starttls)
      new_bits += "StartTLS";
    if (bookinfo.sasl) {
      if (bookinfo.starttls)
        new_bits += ",";
      new_bits += "SASL";
      if (!bookinfo.saslMech.empty())
        new_bits += "=" + bookinfo.saslMech;
    }
  }

  if (ldap_url_parse (new_bits.c_str(), &url_base))
    errmsg += _("Invalid Server URI\n");

  if (!errmsg.empty()) {
    return -1;
  }

  url_host->lud_dn = ldap_strdup (base.c_str());
  url_host->lud_attrs = url_base->lud_attrs;
  url_host->lud_scope = url_base->lud_scope;
  url_host->lud_filter = url_base->lud_filter;
  if (!url_host->lud_exts) {
    url_host->lud_exts = url_base->lud_exts;
    url_base->lud_exts = NULL;
  }
  url_base->lud_attrs = NULL;
  url_base->lud_filter = NULL;
  ldap_free_urldesc (url_base);

  bookinfo.urld = boost::shared_ptr<LDAPURLDesc> (url_host, ldap_url_desc_deleter ());
  url_str = ldap_url_desc2str (url_host);
  bookinfo.uri = std::string(url_str);
  ldap_memfree (url_str);

  {
    size_t pos;
    pos = bookinfo.uri.find ('/', strlen(url_host->lud_scheme) + 3);
    if (pos != std::string::npos)
      bookinfo.uri_host = bookinfo.uri.substr (0,pos);
    else
      bookinfo.uri_host = bookinfo.uri;
  }
  return 0;
}
Exemple #17
0
void
Local::Presentity::edit_presentity_form_submitted (bool submitted,
						   Ekiga::Form &result)
{
  if (!submitted)
    return;

  const std::string new_name = result.text ("name");
  const std::set<std::string> groups = get_groups ();
  const std::set<std::string> new_groups = result.editable_set ("groups");
  std::string new_uri = result.text ("uri");
  const std::string uri = get_uri ();
  bool preferred = result.boolean ("preferred");
  std::set<xmlNodePtr> nodes_to_remove;

  new_uri = canonize_uri (new_uri);

  for (xmlNodePtr child = node->children ;
       child != NULL ;
       child = child->next) {

    if (child->type == XML_ELEMENT_NODE
        && child->name != NULL) {

      if (xmlStrEqual (BAD_CAST ("name"), child->name)) {

	robust_xmlNodeSetContent (node, &child, "name", new_name);
      }
    }
  }

  if (uri != new_uri) {

    boost::shared_ptr<Ekiga::PresenceCore> pcore = presence_core.lock ();
    if (pcore) {
      pcore->unfetch_presence (uri);
      pcore->fetch_presence (new_uri);
    }
    presence = "unknown";
    xmlSetProp (node, (const xmlChar*)"uri", (const xmlChar*)new_uri.c_str ());
  }

  // the first loop looks at groups we were in : are we still in ?
  for (xmlNodePtr child = node->children ;
       child != NULL ;
       child = child->next) {

    if (child->type == XML_ELEMENT_NODE
        && child->name != NULL) {

      if (xmlStrEqual (BAD_CAST ("group"), child->name)) {

	xmlChar* xml_str = xmlNodeGetContent (child);

	if (xml_str != NULL) {

	  if (new_groups.find ((const char*) xml_str) == new_groups.end ()) {

	    nodes_to_remove.insert (child); // don't free what we loop on!
	  }
	  xmlFree (xml_str);
	}
      }
    }
  }

  // ok, now we can clean up!
  for (std::set<xmlNodePtr>::iterator iter = nodes_to_remove.begin ();
       iter != nodes_to_remove.end ();
       ++iter) {

    xmlUnlinkNode (*iter);
    xmlFreeNode (*iter);
  }

  // the second loop looking for groups we weren't in but are now
  for (std::set<std::string>::const_iterator iter = new_groups.begin ();
       iter != new_groups.end ();
       iter++) {

    if (std::find (groups.begin (), groups.end (), *iter) == groups.end ()) {
      xmlNewChild (node, NULL,
		   BAD_CAST "group",
		   BAD_CAST robust_xmlEscape (node->doc, *iter).c_str ());
    }
  }

  if (preferred) {

    xmlSetProp (node, BAD_CAST "preferred", BAD_CAST "true");
  } else {

    xmlSetProp (node, BAD_CAST "preferred", BAD_CAST "false");
  }

  updated ();
  trigger_saving ();
}