예제 #1
0
void ForkExecParent::setupPipe(GIOChannel *&channel, guint &sourceID, int fd)
{
    if (fd == -1) {
        // nop
        return;
    }

    channel = g_io_channel_unix_new(fd);
    if (!channel) {
        // failure
        SE_LOG_DEBUG(NULL, NULL, "g_io_channel_unix_new() returned NULL");
        close(fd);
        return;
    }
    // Close fd when freeing the channel (done by caller).
    g_io_channel_set_close_on_unref(channel, true);
    // Don't block in outputReady().
    GErrorCXX error;
    g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, error);
    // We assume that the helper is writing data in the same encoding
    // and thus avoid any kind of conversion. Necessary to avoid
    // buffering.
    error.clear();
    g_io_channel_set_encoding(channel, NULL, error);
    g_io_channel_set_buffered(channel, true);
    sourceID = g_io_add_watch(channel, (GIOCondition)(G_IO_IN|G_IO_ERR|G_IO_HUP), outputReady, this);
}
void EvolutionContactSource::listAllItems(RevisionMap_t &revisions)
{
#ifdef USE_EBOOK_CLIENT
    GErrorCXX gerror;
    EBookClientView *view;

    EBookQueryCXX allItemsQuery(e_book_query_any_field_contains(""), false);
    PlainGStr sexp(e_book_query_to_string (allItemsQuery.get()));
    
    if (!e_book_client_get_view_sync(m_addressbook, sexp, &view, NULL, gerror)) {
        throwError( "getting the view" , gerror);
    }
    EBookClientViewCXX viewPtr = EBookClientViewCXX::steal(view);

    // Optimization: set fields_of_interest (UID / REV)
    GListCXX<const char, GSList> interesting_field_list;
    interesting_field_list.push_back(e_contact_field_name (E_CONTACT_UID));
    interesting_field_list.push_back(e_contact_field_name (E_CONTACT_REV));
    e_book_client_view_set_fields_of_interest (viewPtr, interesting_field_list, gerror);
    if (gerror) {
        SE_LOG_ERROR(this, NULL, "e_book_client_view_set_fields_of_interest: %s", (const char*)gerror);
        gerror.clear();
    }

    EBookClientViewSyncHandler handler(viewPtr, list_revisions, &revisions);
    if (!handler.process(gerror)) {
        throwError("watching view", gerror);
    }
#else
    GErrorCXX gerror;
    eptr<EBookQuery> allItemsQuery(e_book_query_any_field_contains(""), "query");
    GList *nextItem;
    if (!e_book_get_contacts(m_addressbook, allItemsQuery, &nextItem, gerror)) {
        throwError( "reading all items", gerror );
    }
    eptr<GList> listptr(nextItem);
    while (nextItem) {
        EContact *contact = E_CONTACT(nextItem->data);
        if (!contact) {
            throwError("contact entry without data");
        }
        pair<string, string> revmapping;
        const char *uid = (const char *)e_contact_get_const(contact,
                                                            E_CONTACT_UID);
        if (!uid || !uid[0]) {
            throwError("contact entry without UID");
        }
        revmapping.first = uid;
        const char *rev = (const char *)e_contact_get_const(contact,
                                                            E_CONTACT_REV);
        if (!rev || !rev[0]) {
            throwError(string("contact entry without REV: ") + revmapping.first);
        }
        revmapping.second = rev;
        revisions.insert(revmapping);
        nextItem = nextItem->next;
    }
#endif
}
EvolutionSyncSource::Databases EvolutionContactSource::getDatabases()
{
    ESourceList *sources = NULL;

#ifdef USE_EBOOK_CLIENT
    if (!e_book_client_get_sources(&sources, NULL)) {
#else
    if (!e_book_get_addressbooks(&sources, NULL)) {
#endif
        SyncContext::throwError("unable to access address books");
    }

    Databases secondary;
    Databases result;
    for (GSList *g = e_source_list_peek_groups (sources); g; g = g->next) {
        ESourceGroup *group = E_SOURCE_GROUP (g->data);
        for (GSList *s = e_source_group_peek_sources (group); s; s = s->next) {
            ESource *source = E_SOURCE (s->data);
            eptr<char> uri(e_source_get_uri(source));
            string uristr;
            if (uri) {
                uristr = uri.get();
            }
            Database entry(e_source_peek_name(source),
                           uristr,
                           false);
            if (boost::starts_with(uristr, "couchdb://")) {
                // Append CouchDB address books at the end of the list,
                // otherwise preserving the order of address books.
                //
                // The reason is Moblin Bugzilla #7877 (aka CouchDB
                // feature request #479110): the initial release of
                // evolution-couchdb in Ubuntu 9.10 is unusable because
                // it does not support the REV property.
                //
                // Reordering the entries ensures that the CouchDB
                // address book is not used as the default database by
                // SyncEvolution, as it happened in Ubuntu 9.10.
                // Users can still pick it intentionally via
                // "evolutionsource".
                secondary.push_back(entry);
            } else {
                result.push_back(entry);
            }
        }
    }
    result.insert(result.end(), secondary.begin(), secondary.end());

    // No results? Try system address book (workaround for embedded Evolution Dataserver).
    if (!result.size()) {
#ifdef USE_EBOOK_CLIENT
        EBookClientCXX book;
        const char *name;

        name = "<<system>>";
        book = EBookClientCXX::steal(e_book_client_new_system (NULL));
        if (!book) {
            name = "<<default>>";
            book = EBookClientCXX::steal(e_book_client_new_default (NULL));
        }

        if (book) {
            const char *uri = e_client_get_uri (E_CLIENT ((EBookClient*)book));
            result.push_back(Database(name, uri, true));
        }
#else
        eptr<EBook, GObject> book;
        GErrorCXX gerror;
        const char *name;

        name = "<<system>>";
        book = e_book_new_system_addressbook (gerror);
        gerror.clear();
        if (!book) {
            name = "<<default>>";
            book = e_book_new_default_addressbook (gerror);
        }

        if (book) {
            const char *uri = e_book_get_uri (book);
            result.push_back(Database(name, uri, true));
        }
#endif
    } else {
        //  the first DB found is the default
        result[0].m_isDefault = true;
    }
    
    return result;
}

#ifdef USE_EBOOK_CLIENT
static void
handle_error_cb (EClient */*client*/, const gchar *error_msg, gpointer user_data)
{
    EvolutionContactSource *that = static_cast<EvolutionContactSource *>(user_data);
    SE_LOG_ERROR(that, NULL, "%s", error_msg);
}
void EvolutionContactSource::open()
{
    GErrorCXX gerror;
    bool created = false;
    bool onlyIfExists = false; // always try to create address book, because even if there is
                               // a source there's no guarantee that the actual database was
                               // created already; the original logic below for only setting
                               // this when explicitly requesting a new address book
                               // therefore failed in some cases
#ifdef USE_EBOOK_CLIENT
    ESourceList *tmp;
    if (!e_book_client_get_sources(&tmp, gerror)) {
        throwError("unable to access address books", gerror);
    }
    ESourceListCXX sources(tmp, false);

    string id = getDatabaseID();
    ESource *source = findSource(sources, id);
    if (!source) {
        // might have been special "<<system>>" or "<<default>>", try that and
        // creating address book from file:// URI before giving up
        if (id.empty() || id == "<<system>>") {
            m_addressbook = EBookClientCXX::steal(e_book_client_new_system (gerror));
        } else if (id.empty() || id == "<<default>>") {
            m_addressbook = EBookClientCXX::steal(e_book_client_new_default (gerror));
        } else if (boost::starts_with(id, "file://")) {
            m_addressbook = EBookClientCXX::steal(e_book_client_new_from_uri(id.c_str(), gerror));
        } else {
            throwError(string(getName()) + ": no such address book: '" + id + "'");
        }
        created = true;
    } else {
        m_addressbook = EBookClientCXX::steal(e_book_client_new( source, gerror ));
    }

    if (gerror) {
        throwError("create addressbook", gerror);
    }

    // Listen for errors
    g_signal_connect (m_addressbook, "backend-error", G_CALLBACK (handle_error_cb), this); 

    // Handle authentication requests from the backend
    g_signal_connect (m_addressbook, "authenticate", G_CALLBACK (handle_authentication_cb), this);
 
    // Open the address book
    if (!e_client_open_sync( E_CLIENT ((EBookClient*)m_addressbook), onlyIfExists, NULL, gerror) ) {
        if (created) {
            // opening newly created address books often fails, try again once more
            gerror.clear();
            sleep(5);
            if (!e_client_open_sync( E_CLIENT ((EBookClient*)m_addressbook), onlyIfExists, NULL, gerror)) {
                throwError("opening address book", gerror);
            }
        } else {
            throwError("opening address book", gerror);
        }
    }

    g_signal_connect_after(m_addressbook,
                           "backend-died",
                           G_CALLBACK(SyncContext::fatalError),
                           (void *)"Evolution Data Server has died unexpectedly, contacts no longer available.");
#else
    ESourceList *tmp;
    if (!e_book_get_addressbooks(&tmp, gerror)) {
        throwError("unable to access address books", gerror);
    }
    ESourceListCXX sources(tmp, false);

    string id = getDatabaseID();
    ESource *source = findSource(sources, id);
    if (!source) {
        // might have been special "<<system>>" or "<<default>>", try that and
        // creating address book from file:// URI before giving up
        if (id.empty() || id == "<<system>>") {
            m_addressbook.set( e_book_new_system_addressbook (gerror), "system address book" );
        } else if (id.empty() || id == "<<default>>") {
            m_addressbook.set( e_book_new_default_addressbook (gerror), "default address book" );
        } else if (boost::starts_with(id, "file://")) {
            m_addressbook.set(e_book_new_from_uri(id.c_str(), gerror), "creating address book");
        } else {
            throwError(string(getName()) + ": no such address book: '" + id + "'");
        }
        created = true;
    } else {
        m_addressbook.set( e_book_new( source, gerror ), "address book" );
    }
 
    if (!e_book_open( m_addressbook, onlyIfExists, gerror) ) {
        if (created) {
            // opening newly created address books often fails, try again once more
            sleep(5);
            if (!e_book_open(m_addressbook, onlyIfExists, gerror)) {
                throwError("opening address book", gerror);
            }
        } else {
            throwError("opening address book", gerror);
        }
    }

    // users are not expected to configure an authentication method,
    // so pick one automatically if the user indicated that he wants authentication
    // by setting user or password
    std::string user = getUser(),
        passwd = getPassword();
    if (!user.empty() || !passwd.empty()) {
        GList *authmethod;
        if (!e_book_get_supported_auth_methods(m_addressbook, &authmethod, gerror)) {
            throwError("getting authentication methods", gerror);
        }
        while (authmethod) {
            const char *method = (const char *)authmethod->data;
            SE_LOG_DEBUG(this, NULL, "trying authentication method \"%s\", user %s, password %s",
                         method,
                         !user.empty() ? "configured" : "not configured",
                         !passwd.empty() ? "configured" : "not configured");
            if (e_book_authenticate_user(m_addressbook,
                                         user.c_str(),
                                         passwd.c_str(),
                                         method,
                                         gerror)) {
                SE_LOG_DEBUG(this, NULL, "authentication succeeded");
                break;
            } else {
                SE_LOG_ERROR(this, NULL, "authentication failed: %s", gerror->message);
            }
            authmethod = authmethod->next;
        }
    }

    g_signal_connect_after(m_addressbook,
                           "backend-died",
                           G_CALLBACK(SyncContext::fatalError),
                           (void *)"Evolution Data Server has died unexpectedly, contacts no longer available.");
#endif
}