• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

KLDAP Library

ldapoperation.cpp

00001 /*
00002   This file is part of libkldap.
00003   Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
00004 
00005   This library is free software; you can redistribute it and/or
00006   modify it under the terms of the GNU Library General  Public
00007   License as published by the Free Software Foundation; either
00008   version 2 of the License, or (at your option) any later version.
00009 
00010   This library is distributed in the hope that it will be useful,
00011   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013   Library General Public License for more details.
00014 
00015   You should have received a copy of the GNU Library General Public License
00016   along with this library; see the file COPYING.LIB.  If not, write to
00017   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018   Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "ldapoperation.h"
00022 #include "kldap_config.h"
00023 
00024 #include <kdebug.h>
00025 
00026 #include <QtCore/QTime>
00027 
00028 #include <stdlib.h>
00029 #ifdef HAVE_SYS_TIME_H
00030 #include <sys/time.h>
00031 #endif
00032 
00033 #ifdef SASL2_FOUND
00034 #include <sasl/sasl.h>
00035 #endif
00036 
00037 #ifdef LDAP_FOUND
00038 #include <lber.h>
00039 #include <ldap.h>
00040 #endif
00041 
00042 #include "ldapdefs.h"
00043 
00044 using namespace KLDAP;
00045 
00046 #ifdef LDAP_FOUND
00047 static void extractControls( LdapControls &ctrls, LDAPControl **pctrls );
00048 #endif // LDAP_FOUND
00049 
00050 /*
00051    Returns the difference between msecs and elapsed. If msecs is -1,
00052    however, -1 is returned.
00053 */
00054 static int kldap_timeout_value( int msecs, int elapsed )
00055 {
00056   if ( msecs == -1 ) {
00057     return -1;
00058   }
00059 
00060   int timeout = msecs - elapsed;
00061   return timeout < 0 ? 0 : timeout;
00062 }
00063 
00064 class LdapOperation::LdapOperationPrivate {
00065 public:
00066   LdapOperationPrivate();
00067   ~LdapOperationPrivate();
00068 #ifdef LDAP_FOUND
00069   int processResult( int rescode, LDAPMessage *msg );
00070   int bind( const QByteArray &creds, SASL_Callback_Proc *saslproc, void *data, bool async );
00071 #endif
00072   LdapControls mClientCtrls, mServerCtrls, mControls;
00073   LdapObject mObject;
00074   QByteArray mExtOid, mExtData;
00075   QByteArray mServerCred;
00076   QString mMatchedDn;
00077   QList<QByteArray> mReferrals;
00078 
00079   LdapConnection *mConnection;
00080 };
00081 
00082 LdapOperation::LdapOperation()
00083   : d( new LdapOperationPrivate )
00084 {
00085   d->mConnection = 0;
00086 }
00087 
00088 LdapOperation::LdapOperation( LdapConnection &conn )
00089   : d( new LdapOperationPrivate )
00090 {
00091   setConnection( conn );
00092 }
00093 
00094 LdapOperation::~LdapOperation()
00095 {
00096   delete d;
00097 }
00098 
00099 void LdapOperation::setConnection( LdapConnection &conn )
00100 {
00101   d->mConnection = &conn;
00102 }
00103 
00104 LdapConnection &LdapOperation::connection()
00105 {
00106   return *d->mConnection;
00107 }
00108 
00109 void LdapOperation::setClientControls( const LdapControls &ctrls )
00110 {
00111   d->mClientCtrls = ctrls;
00112 }
00113 
00114 void LdapOperation::setServerControls( const LdapControls &ctrls )
00115 {
00116   d->mServerCtrls = ctrls;
00117 }
00118 
00119 LdapControls LdapOperation::clientControls() const
00120 {
00121   return d->mClientCtrls;
00122 }
00123 
00124 LdapControls LdapOperation::serverControls() const
00125 {
00126   return d->mServerCtrls;
00127 }
00128 
00129 LdapObject LdapOperation::object() const
00130 {
00131   return d->mObject;
00132 }
00133 
00134 LdapControls LdapOperation::controls() const
00135 {
00136   return d->mControls;
00137 }
00138 
00139 QByteArray LdapOperation::extendedOid() const
00140 {
00141   return d->mExtOid;
00142 }
00143 
00144 QByteArray LdapOperation::extendedData() const
00145 {
00146   return d->mExtData;
00147 }
00148 
00149 QString LdapOperation::matchedDn() const
00150 {
00151   return d->mMatchedDn;
00152 }
00153 
00154 QList<QByteArray> LdapOperation::referrals() const
00155 {
00156   return d->mReferrals;
00157 }
00158 
00159 QByteArray LdapOperation::serverCred() const
00160 {
00161   return d->mServerCred;
00162 }
00163 
00164 LdapOperation::LdapOperationPrivate::LdapOperationPrivate()
00165 {
00166 }
00167 
00168 LdapOperation::LdapOperationPrivate::~LdapOperationPrivate()
00169 {
00170 }
00171 
00172 #ifdef LDAP_FOUND
00173 
00174 #ifdef SASL2_FOUND
00175 static int kldap_sasl_interact( sasl_interact_t *interact, LdapOperation::SASL_Data *data )
00176 {
00177   if ( data->proc ) {
00178     for ( ; interact->id != SASL_CB_LIST_END; interact++ ) {
00179       switch ( interact->id ) {
00180         case SASL_CB_GETREALM:
00181           data->creds.fields |= LdapOperation::SASL_Realm;
00182           break;
00183         case SASL_CB_AUTHNAME:
00184           data->creds.fields |= LdapOperation::SASL_Authname;
00185           break;
00186         case SASL_CB_PASS:
00187           data->creds.fields |= LdapOperation::SASL_Password;
00188           break;
00189         case SASL_CB_USER:
00190           data->creds.fields |= LdapOperation::SASL_Authzid;
00191           break;
00192       }
00193     }
00194     int retval;
00195     if ( (retval = data->proc( data->creds, data->data )) ) {
00196       return retval;
00197     }
00198   }
00199 
00200   QString value;
00201 
00202   while ( interact->id != SASL_CB_LIST_END ) {
00203     value = QString();
00204     switch( interact->id ) {
00205       case SASL_CB_GETREALM:
00206         value = data->creds.realm;
00207         kDebug(5322) << "SASL_REALM=" << value << endl;
00208         break;
00209       case SASL_CB_AUTHNAME:
00210         value = data->creds.authname;
00211         kDebug(5322) << "SASL_AUTHNAME=" << value << endl;
00212         break;
00213       case SASL_CB_PASS:
00214         value = data->creds.password;
00215         kDebug(5322) << "SASL_PASSWD=[hidden]" << endl;
00216         break;
00217       case SASL_CB_USER:
00218         value = data->creds.authzid;
00219         kDebug(5322) << "SASL_AUTHZID=" << value << endl;
00220         break;
00221     }
00222     if ( value.isEmpty() ) {
00223     interact->result = NULL;
00224     interact->len = 0;
00225     } else {
00226     interact->result = strdup( value.toUtf8() );
00227     interact->len = strlen( (const char *) interact->result );
00228     }
00229     interact++;
00230   }
00231   return KLDAP_SUCCESS;
00232 }
00233 #endif
00234 
00235 int LdapOperation::LdapOperationPrivate::bind( const QByteArray &creds, SASL_Callback_Proc *saslproc, void *data, bool async )
00236 {
00237   Q_ASSERT( mConnection );
00238   LDAP *ld = (LDAP*) mConnection->handle();
00239   LdapServer server;
00240   server = mConnection->server();
00241 
00242   int ret;
00243 
00244   if ( server.auth() == LdapServer::SASL ) {
00245 #ifdef SASL2_FOUND
00246     sasl_conn_t *saslconn = (sasl_conn_t*) mConnection->saslHandle();
00247     sasl_interact_t *client_interact = NULL;
00248     const char *out = NULL;
00249     uint outlen;
00250     const char *mechusing = NULL;
00251     struct berval ccred, *scred;
00252     int saslresult;
00253     QByteArray sdata = creds;
00254 
00255     QString mech = server.mech();
00256     if ( mech.isEmpty() ) {
00257       mech = "DIGEST-MD5";
00258     }
00259 
00260     SASL_Data sasldata;
00261     sasldata.proc = saslproc;
00262     sasldata.data = data;
00263     sasldata.creds.fields = 0;
00264     sasldata.creds.realm = server.realm();
00265     sasldata.creds.authname = server.user();
00266     sasldata.creds.authzid = server.bindDn();
00267     sasldata.creds.password = server.password();
00268 
00269     do {
00270     if ( sdata.isEmpty() ) {
00271         do {
00272             saslresult = sasl_client_start(saslconn, mech.toLatin1(),
00273                 &client_interact, &out, &outlen, &mechusing);
00274                       
00275         if ( saslresult == SASL_INTERACT )
00276             if ( kldap_sasl_interact( client_interact, &sasldata ) != KLDAP_SUCCESS ) {
00277                     return KLDAP_SASL_ERROR;
00278                 };
00279         kDebug(5322) << "sasl_client_start mech: " << mechusing << " outlen " << outlen << " result: " << saslresult;
00280             } while ( saslresult == SASL_INTERACT );
00281         if ( saslresult != SASL_CONTINUE && saslresult != SASL_OK ) {
00282         return KLDAP_SASL_ERROR;
00283         }
00284         
00285     } else {
00286         kDebug(5322) << "sasl_client_step";
00287         do {
00288         saslresult = sasl_client_step(saslconn, sdata.data(), sdata.size(),
00289             &client_interact, &out, &outlen);
00290         if ( saslresult == SASL_INTERACT )
00291             if ( kldap_sasl_interact( client_interact, &sasldata ) != KLDAP_SUCCESS ) {
00292                     return KLDAP_SASL_ERROR;
00293                 };
00294             } while ( saslresult == SASL_INTERACT );
00295         kDebug(5322) << "sasl_client_step result" << saslresult;
00296         if ( saslresult != SASL_CONTINUE && saslresult != SASL_OK ) {
00297         return KLDAP_SASL_ERROR;
00298         }
00299     }
00300     
00301     ccred.bv_val = (char*) out;
00302     ccred.bv_len = outlen;
00303     
00304     if ( async ) {
00305         kDebug(5322) << "ldap_sasl_bind";
00306         int msgid;
00307         ret = ldap_sasl_bind( ld, server.bindDn().toUtf8().data(), mech.toLatin1(), 
00308         &ccred, 0, 0, &msgid );
00309         if ( ret == 0 ) {
00310           ret = msgid;
00311         }
00312         kDebug(5322) << "ldap_sasl_bind msgid" << ret;
00313     } else {
00314         kDebug(5322) << "ldap_sasl_bind_s";
00315         ret = ldap_sasl_bind_s( ld, server.bindDn().toUtf8().data(), mech.toLatin1(), 
00316         &ccred, 0, 0, &scred );
00317         kDebug(5322) << "ldap_sasl_bind_s ret" << ret;
00318         if ( scred ) {
00319         sdata = QByteArray( scred->bv_val, scred->bv_len );
00320         } else {
00321         sdata = QByteArray();
00322         }
00323     }
00324     } while ( !async && ret == KLDAP_SASL_BIND_IN_PROGRESS );
00325 #else
00326     kError() << "SASL authentication is not available (re-compile kldap with cyrus-sasl development).";
00327     return KLDAP_SASL_ERROR;
00328 #endif
00329   } else { //simple auth
00330     QByteArray bindname,pass;
00331     struct berval ccred;
00332     if ( server.auth() == LdapServer::Simple ) {
00333       bindname = server.bindDn().toUtf8();
00334       pass = server.password().toUtf8();
00335     }
00336     ccred.bv_val = pass.data();
00337     ccred.bv_len = pass.size();
00338     kDebug(5322) << "binding to server, bindname: " << bindname << " password: *****";
00339     
00340     if ( async ) {
00341     kDebug(5322) << "ldap_sasl_bind (simple)";
00342     int msgid;
00343     ret = ldap_sasl_bind( ld, bindname.data(), 0, &ccred, 0, 0, &msgid );
00344 //  ret = ldap_simple_bind( ld, bindname.data(),pass.data() );
00345     if ( ret == 0 ) {
00346         ret = msgid;
00347     }
00348     } else {
00349     kDebug(5322) << "ldap_sasl_bind_s (simple)";
00350     ret = ldap_sasl_bind_s( ld, bindname.data(), 0, &ccred, 0, 0, 0 );
00351 //  ret = ldap_simple_bind_s( ld, bindname.data(), pass.data() );
00352     }
00353   }
00354   return ret;
00355 }
00356 
00357 int LdapOperation::LdapOperationPrivate::processResult( int rescode, LDAPMessage *msg )
00358 {
00359   //kDebug(5322) << "LdapOperation::LdapOperationPrivate::processResult()";
00360   int retval;
00361   LDAP *ld = (LDAP*) mConnection->handle();
00362 
00363   kDebug(5322) << "processResult() rescode: " << rescode;
00364   switch ( rescode ) {
00365     case RES_SEARCH_ENTRY:
00366     {
00367       //kDebug(5322) << "LdapOperation::LdapOperationPrivate::processResult():"
00368       //             << "Found search entry";
00369       mObject.clear();
00370       LdapAttrMap attrs;
00371       char *name;
00372       struct berval **bvals;
00373       BerElement     *entry;
00374 
00375       char *dn = ldap_get_dn( ld, msg );
00376       mObject.setDn( QString::fromUtf8( dn ) );
00377       ldap_memfree( dn );
00378 
00379       // iterate over the attributes
00380       name = ldap_first_attribute( ld, msg, &entry );
00381       while ( name != 0 ) {
00382         // print the values
00383         bvals = ldap_get_values_len( ld, msg, name );
00384         LdapAttrValue values;
00385         if ( bvals ) {
00386           for ( int i = 0; bvals[i] != 0; i++ ) {
00387             char *val = bvals[i]->bv_val;
00388             unsigned long len = bvals[i]->bv_len;
00389             values.append( QByteArray( val, len ) );
00390           }
00391           ldap_value_free_len( bvals );
00392         }
00393         attrs[ QString::fromLatin1( name ) ] = values;
00394         ldap_memfree( name );
00395         
00396         // next attribute
00397         name = ldap_next_attribute( ld, msg, entry );
00398       }
00399       ber_free( entry , 0 );
00400       mObject.setAttributes( attrs );
00401       break;
00402     }
00403     case RES_EXTENDED:
00404     {
00405       char *retoid;
00406       struct berval *retdata;
00407       retval = ldap_parse_extended_result( ld, msg, &retoid, &retdata, 0 );
00408       if ( retval != KLDAP_SUCCESS ) {
00409         ldap_msgfree( msg );
00410         return -1;
00411       }
00412       mExtOid = retoid ? QByteArray( retoid ) : QByteArray();
00413       mExtData = retdata ? QByteArray( retdata->bv_val, retdata->bv_len ) : QByteArray();
00414       ldap_memfree( retoid );
00415       ber_bvfree( retdata );
00416       break;
00417     }
00418     case RES_BIND:
00419     {
00420       struct berval *servercred;
00421       retval = ldap_parse_sasl_bind_result( ld, msg, &servercred, 0 );
00422       if ( retval != KLDAP_SUCCESS && retval != KLDAP_SASL_BIND_IN_PROGRESS ) {
00423         kDebug(5322) << "RES_BIND error: " << retval;
00424         ldap_msgfree( msg );
00425         return -1;
00426       }
00427       kDebug(5322) << "RES_BIND rescode" << rescode << "retval:" << retval;
00428       mServerCred = servercred ? QByteArray( servercred->bv_val, servercred->bv_len ) : QByteArray();
00429       ber_bvfree( servercred );
00430       break;
00431     }
00432     default:
00433     {
00434       LDAPControl **serverctrls = 0;
00435       char *matcheddn = 0, *errmsg = 0;
00436       char **referralsp;
00437       int errcodep;
00438       retval =
00439           ldap_parse_result( ld, msg, &errcodep, &matcheddn, &errmsg, &referralsp,
00440                              &serverctrls, 0 );
00441       kDebug(5322) << "rescode" << rescode << "retval:" << retval
00442                    << "matcheddn:" << matcheddn << "errcode:"
00443                    << errcodep << "errmsg:" << errmsg;
00444       if ( retval != KLDAP_SUCCESS ) {
00445         ldap_msgfree( msg );
00446         return -1;
00447       }
00448       mControls.clear();
00449       if ( serverctrls ) {
00450         extractControls( mControls, serverctrls );
00451         ldap_controls_free( serverctrls );
00452       }
00453       mReferrals.clear();
00454       if ( referralsp ) {
00455         char **tmp = referralsp;
00456         while ( *tmp ) {
00457           mReferrals.append( QByteArray( *tmp ) );
00458           ldap_memfree( *tmp );
00459           tmp++;
00460         }
00461         ldap_memfree( (char *) referralsp );
00462       }
00463       mMatchedDn = QString();
00464       if ( matcheddn ) {
00465         mMatchedDn = QString::fromUtf8( matcheddn );
00466         ldap_memfree( matcheddn );
00467       }
00468       if ( errmsg ) {
00469         ldap_memfree( errmsg );
00470       }
00471     }
00472   }
00473 
00474   ldap_msgfree( msg );
00475 
00476   return rescode;
00477 }
00478 
00479 static void addModOp( LDAPMod ***pmods, int mod_type, const QString &attr,
00480                       const QByteArray *value = 0 )
00481 {
00482   //  kDebug(5322) << "type:" << mod_type << "attr:" << attr <<
00483   //    "value:" << QString::fromUtf8(value,value.size()) <<
00484   //    "size:" << value.size();
00485   LDAPMod **mods;
00486 
00487   mods = *pmods;
00488 
00489   uint i = 0;
00490 
00491   if ( mods == 0 ) {
00492     mods = (LDAPMod **) malloc ( 2 * sizeof( LDAPMod * ) );
00493     mods[ 0 ] = (LDAPMod *) malloc( sizeof( LDAPMod ) );
00494     mods[ 1 ] = 0;
00495     memset( mods[ 0 ], 0, sizeof( LDAPMod ) );
00496   } else {
00497     while ( mods[ i ] != 0 &&
00498             ( strcmp( attr.toUtf8(), mods[i]->mod_type ) != 0 ||
00499               ( mods[ i ]->mod_op & ~LDAP_MOD_BVALUES ) != mod_type ) ) i++;
00500 
00501     if ( mods[ i ] == 0 ) {
00502       mods = (LDAPMod **)realloc( mods, ( i + 2 ) * sizeof( LDAPMod * ) );
00503       if ( mods == 0 ) {
00504         kError() << "addModOp: realloc";
00505         return;
00506       }
00507       mods[ i + 1 ] = 0;
00508       mods[ i ] = (LDAPMod *) malloc( sizeof( LDAPMod ) );
00509       memset( mods[ i ], 0, sizeof( LDAPMod ) );
00510     }
00511   }
00512 
00513   mods[ i ]->mod_op = mod_type | LDAP_MOD_BVALUES;
00514   if ( mods[ i ]->mod_type == 0 ) {
00515     mods[ i ]->mod_type = strdup( attr.toUtf8() );
00516   }
00517 
00518   *pmods = mods;
00519 
00520   if ( value == 0 ) 
00521     return;
00522 
00523   int vallen = value->size();
00524   BerValue *berval;
00525   berval = (BerValue *) malloc( sizeof( BerValue ) );
00526   berval -> bv_len = vallen;
00527   if ( vallen > 0 ) {
00528     berval -> bv_val = (char *) malloc( vallen );
00529     memcpy( berval -> bv_val, value->data(), vallen );
00530   } else {
00531     berval -> bv_val = 0;
00532   }
00533 
00534   if ( mods[ i ] -> mod_vals.modv_bvals == 0 ) {
00535     mods[ i ]->mod_vals.modv_bvals =
00536       (BerValue **) malloc( sizeof( BerValue * ) * 2 );
00537     mods[ i ]->mod_vals.modv_bvals[ 0 ] = berval;
00538     mods[ i ]->mod_vals.modv_bvals[ 1 ] = 0;
00539 //    kDebug(5322) << "addModOp: new bervalue struct" << attr << value;
00540   } else {
00541     uint j = 0;
00542     while ( mods[ i ]->mod_vals.modv_bvals[ j ] != 0 ) {
00543       j++;
00544     }
00545     mods[ i ]->mod_vals.modv_bvals =
00546       (BerValue **) realloc( mods[ i ]->mod_vals.modv_bvals,
00547                              ( j + 2 ) * sizeof( BerValue * ) );
00548     if ( mods[ i ]->mod_vals.modv_bvals == 0 ) {
00549       kError() << "addModOp: realloc";
00550       free( berval );
00551       return;
00552     }
00553     mods[ i ]->mod_vals.modv_bvals[ j ] = berval;
00554     mods[ i ]->mod_vals.modv_bvals[ j+1 ] = 0;
00555     kDebug(5322) << j << ". new bervalue";
00556   }
00557 }
00558 
00559 static void addControlOp( LDAPControl ***pctrls, const QString &oid,
00560                           const QByteArray &value, bool critical )
00561 {
00562   LDAPControl **ctrls;
00563   LDAPControl *ctrl = (LDAPControl *) malloc( sizeof( LDAPControl ) );
00564 
00565   ctrls = *pctrls;
00566 
00567   kDebug(5322) << "addControlOp: oid:'" << oid << "' val: '" << value << "'";
00568   int vallen = value.size();
00569   ctrl->ldctl_value.bv_len = vallen;
00570   if ( vallen ) {
00571     ctrl->ldctl_value.bv_val = (char *) malloc( vallen );
00572     memcpy( ctrl->ldctl_value.bv_val, value.data(), vallen );
00573   } else {
00574     ctrl->ldctl_value.bv_val = 0;
00575   }
00576   ctrl->ldctl_iscritical = critical;
00577   ctrl->ldctl_oid = strdup( oid.toUtf8() );
00578 
00579   uint i = 0;
00580 
00581   if ( ctrls == 0 ) {
00582     ctrls = (LDAPControl **) malloc ( 2 * sizeof( LDAPControl * ) );
00583     ctrls[ 0 ] = 0;
00584     ctrls[ 1 ] = 0;
00585   } else {
00586     while ( ctrls[ i ] != 0 ) {
00587       i++;
00588     }
00589     ctrls[ i + 1 ] = 0;
00590     ctrls =
00591       (LDAPControl **) realloc( ctrls, ( i + 2 ) * sizeof( LDAPControl * ) );
00592   }
00593   ctrls[ i ] = ctrl;
00594   *pctrls = ctrls;
00595 }
00596 
00597 static void createControls( LDAPControl ***pctrls, const LdapControls &ctrls )
00598 {
00599   for ( int i = 0; i< ctrls.count(); ++i ) {
00600     addControlOp( pctrls, ctrls[i].oid(), ctrls[i].value(), ctrls[i].critical() );
00601   }
00602 }
00603 
00604 static void extractControls( LdapControls &ctrls, LDAPControl **pctrls )
00605 {
00606   LDAPControl *ctrl;
00607   LdapControl control;
00608   int i = 0;
00609 
00610   while ( pctrls[i] ) {
00611     ctrl = pctrls[ i ];
00612     control.setOid( QString::fromUtf8( ctrl->ldctl_oid ) );
00613     control.setValue( QByteArray( ctrl->ldctl_value.bv_val,
00614                                   ctrl->ldctl_value.bv_len ) );
00615     control.setCritical( ctrl->ldctl_iscritical );
00616     ctrls.append( control );
00617     i++;
00618   }
00619 }
00620 
00621 int LdapOperation::bind( const QByteArray &creds, SASL_Callback_Proc *saslproc, void *data )
00622 {
00623   return d->bind( creds, saslproc, data, true );
00624 }
00625 
00626 int LdapOperation::bind_s( SASL_Callback_Proc *saslproc, void *data )
00627 {
00628   return d->bind( QByteArray(), saslproc, data, false );
00629 }
00630 
00631 int LdapOperation::search( const LdapDN &base, LdapUrl::Scope scope,
00632                            const QString &filter, const QStringList &attributes )
00633 {
00634   Q_ASSERT( d->mConnection );
00635   LDAP *ld = (LDAP*) d->mConnection->handle();
00636 
00637   char **attrs = 0;
00638   int msgid;
00639 
00640   LDAPControl **serverctrls = 0, **clientctrls = 0;
00641   createControls( &serverctrls, d->mServerCtrls );
00642   createControls( &serverctrls, d->mClientCtrls );
00643 
00644   int count = attributes.count();
00645   if ( count > 0 ) {
00646     attrs = static_cast<char**>( malloc( ( count + 1 ) * sizeof( char * ) ) );
00647     for ( int i=0; i<count; i++ ) {
00648       attrs[i] = strdup( attributes.at(i).toUtf8() );
00649     }
00650     attrs[count] = 0;
00651   }
00652 
00653   int lscope = LDAP_SCOPE_BASE;
00654   switch ( scope ) {
00655   case LdapUrl::Base:
00656     lscope = LDAP_SCOPE_BASE;
00657     break;
00658   case LdapUrl::One:
00659     lscope = LDAP_SCOPE_ONELEVEL;
00660     break;
00661   case LdapUrl::Sub:
00662     lscope = LDAP_SCOPE_SUBTREE;
00663     break;
00664   }
00665 
00666   kDebug(5322) << "asyncSearch() base=\"" << base.toString() << "\" scope=" << scope <<
00667     "filter=\"" << filter << "\" attrs=" << attributes;
00668   int retval =
00669     ldap_search_ext( ld, base.toString().toUtf8().data(), lscope,
00670                      filter.isEmpty() ? QByteArray("objectClass=*").data() : filter.toUtf8().data(),
00671                      attrs, 0, serverctrls, clientctrls, 0,
00672                      d->mConnection->sizeLimit(), &msgid );
00673 
00674   ldap_controls_free( serverctrls );
00675   ldap_controls_free( clientctrls );
00676 
00677   // free the attributes list again
00678   if ( count > 0 ) {
00679     for ( int i=0; i<count; i++ ) {
00680       free( attrs[i] );
00681     }
00682     free( attrs );
00683   }
00684 
00685   if ( retval == 0 ) {
00686     retval = msgid;
00687   }
00688   return retval;
00689 }
00690 
00691 int LdapOperation::add( const LdapObject &object )
00692 {
00693   Q_ASSERT( d->mConnection );
00694   LDAP *ld = (LDAP*) d->mConnection->handle();
00695 
00696   int msgid;
00697   LDAPMod **lmod = 0;
00698 
00699   LDAPControl **serverctrls = 0, **clientctrls = 0;
00700   createControls( &serverctrls, d->mServerCtrls );
00701   createControls( &serverctrls, d->mClientCtrls );
00702 
00703   for ( LdapAttrMap::ConstIterator it = object.attributes().begin();
00704         it != object.attributes().end(); ++it ) {
00705     QString attr = it.key();
00706     for ( LdapAttrValue::ConstIterator it2 = (*it).begin(); it2 != (*it).end(); ++it2 ) {
00707       addModOp( &lmod, 0, attr, &(*it2) );
00708     }
00709   }
00710 
00711   int retval =
00712     ldap_add_ext( ld, object.dn().toString().toUtf8().data(), lmod, serverctrls,
00713                   clientctrls, &msgid );
00714 
00715   ldap_controls_free( serverctrls );
00716   ldap_controls_free( clientctrls );
00717   ldap_mods_free( lmod, 1 );
00718   if ( retval == 0 ) {
00719     retval = msgid;
00720   }
00721   return retval;
00722 }
00723 
00724 int LdapOperation::add_s( const LdapObject &object )
00725 {
00726   Q_ASSERT( d->mConnection );
00727   LDAP *ld = (LDAP*) d->mConnection->handle();
00728 
00729   LDAPMod **lmod = 0;
00730 
00731   LDAPControl **serverctrls = 0, **clientctrls = 0;
00732   createControls( &serverctrls, d->mServerCtrls );
00733   createControls( &serverctrls, d->mClientCtrls );
00734 
00735   for ( LdapAttrMap::ConstIterator it = object.attributes().begin();
00736         it != object.attributes().end(); ++it ) {
00737     QString attr = it.key();
00738     for ( LdapAttrValue::ConstIterator it2 = (*it).begin(); it2 != (*it).end(); ++it2 ) {
00739       addModOp( &lmod, 0, attr, &(*it2) );
00740     }
00741   }
00742 
00743   int retval =
00744     ldap_add_ext_s( ld, object.dn().toString().toUtf8().data(), lmod, serverctrls,
00745                     clientctrls );
00746 
00747   ldap_controls_free( serverctrls );
00748   ldap_controls_free( clientctrls );
00749   ldap_mods_free( lmod, 1 );
00750   return retval;
00751 }
00752 
00753 int LdapOperation::add( const LdapDN &dn, const ModOps &ops )
00754 {
00755   Q_ASSERT( d->mConnection );
00756   LDAP *ld = (LDAP*) d->mConnection->handle();
00757 
00758   int msgid;
00759   LDAPMod **lmod = 0;
00760 
00761   LDAPControl **serverctrls = 0, **clientctrls = 0;
00762   createControls( &serverctrls, d->mServerCtrls );
00763   createControls( &serverctrls, d->mClientCtrls );
00764 
00765   for ( int i = 0; i < ops.count(); ++i ) {
00766     for ( int j = 0; j < ops[i].values.count(); ++j ) {
00767       addModOp( &lmod, 0, ops[i].attr, &ops[i].values[j] );
00768     }
00769   }
00770 
00771   int retval =
00772     ldap_add_ext( ld, dn.toString().toUtf8().data(), lmod, serverctrls,
00773                   clientctrls, &msgid );
00774 
00775   ldap_controls_free( serverctrls );
00776   ldap_controls_free( clientctrls );
00777   ldap_mods_free( lmod, 1 );
00778   if ( retval == 0 ) {
00779     retval = msgid;
00780   }
00781   return retval;
00782 }
00783 
00784 int LdapOperation::add_s( const LdapDN &dn, const ModOps &ops )
00785 {
00786   Q_ASSERT( d->mConnection );
00787   LDAP *ld = (LDAP*) d->mConnection->handle();
00788 
00789   LDAPMod **lmod = 0;
00790 
00791   LDAPControl **serverctrls = 0, **clientctrls = 0;
00792   createControls( &serverctrls, d->mServerCtrls );
00793   createControls( &serverctrls, d->mClientCtrls );
00794 
00795   for ( int i = 0; i < ops.count(); ++i ) {
00796     for ( int j = 0; j < ops[i].values.count(); ++j ) {
00797       addModOp( &lmod, 0, ops[i].attr, &ops[i].values[j] );
00798     }
00799   }
00800   kDebug(5322) << "LdapOperation::add_s dn=" << dn.toString();
00801   int retval =
00802     ldap_add_ext_s( ld, dn.toString().toUtf8().data(), lmod, serverctrls,
00803                     clientctrls );
00804 
00805   ldap_controls_free( serverctrls );
00806   ldap_controls_free( clientctrls );
00807   ldap_mods_free( lmod, 1 );
00808   return retval;
00809 }
00810 
00811 int LdapOperation::rename( const LdapDN &dn, const QString &newRdn,
00812                            const QString &newSuperior, bool deleteold )
00813 {
00814   Q_ASSERT( d->mConnection );
00815   LDAP *ld = (LDAP*) d->mConnection->handle();
00816 
00817   int msgid;
00818 
00819   LDAPControl **serverctrls = 0, **clientctrls = 0;
00820   createControls( &serverctrls, d->mServerCtrls );
00821   createControls( &serverctrls, d->mClientCtrls );
00822 
00823   int retval = ldap_rename( ld, dn.toString().toUtf8().data(), newRdn.toUtf8().data(),
00824                             newSuperior.isEmpty() ? (char *) 0 : newSuperior.toUtf8().data(),
00825                             deleteold, serverctrls, clientctrls, &msgid );
00826 
00827   ldap_controls_free( serverctrls );
00828   ldap_controls_free( clientctrls );
00829 
00830   if ( retval == 0 ) {
00831     retval = msgid;
00832   }
00833   return retval;
00834 }
00835 
00836 int LdapOperation::rename_s( const LdapDN &dn, const QString &newRdn,
00837                              const QString &newSuperior, bool deleteold )
00838 {
00839   Q_ASSERT( d->mConnection );
00840   LDAP *ld = (LDAP*) d->mConnection->handle();
00841 
00842   LDAPControl **serverctrls = 0, **clientctrls = 0;
00843   createControls( &serverctrls, d->mServerCtrls );
00844   createControls( &serverctrls, d->mClientCtrls );
00845 
00846   int retval = ldap_rename_s( ld, dn.toString().toUtf8().data(), newRdn.toUtf8().data(),
00847                               newSuperior.isEmpty() ? (char *) 0 : newSuperior.toUtf8().data(),
00848                               deleteold, serverctrls, clientctrls );
00849 
00850   ldap_controls_free( serverctrls );
00851   ldap_controls_free( clientctrls );
00852 
00853   return retval;
00854 }
00855 
00856 int LdapOperation::del( const LdapDN &dn )
00857 {
00858   Q_ASSERT( d->mConnection );
00859   LDAP *ld = (LDAP*) d->mConnection->handle();
00860 
00861   int msgid;
00862 
00863   LDAPControl **serverctrls = 0, **clientctrls = 0;
00864   createControls( &serverctrls, d->mServerCtrls );
00865   createControls( &serverctrls, d->mClientCtrls );
00866 
00867   int retval =
00868     ldap_delete_ext( ld, dn.toString().toUtf8().data(), serverctrls, clientctrls, &msgid );
00869 
00870   ldap_controls_free( serverctrls );
00871   ldap_controls_free( clientctrls );
00872 
00873   if ( retval == 0 ) {
00874     retval = msgid;
00875   }
00876   return retval;
00877 }
00878 
00879 int LdapOperation::del_s( const LdapDN &dn )
00880 {
00881   Q_ASSERT( d->mConnection );
00882   LDAP *ld = (LDAP*) d->mConnection->handle();
00883 
00884   LDAPControl **serverctrls = 0, **clientctrls = 0;
00885   createControls( &serverctrls, d->mServerCtrls );
00886   createControls( &serverctrls, d->mClientCtrls );
00887 
00888   int retval = ldap_delete_ext_s( ld, dn.toString().toUtf8().data(), serverctrls, clientctrls );
00889 
00890   ldap_controls_free( serverctrls );
00891   ldap_controls_free( clientctrls );
00892 
00893   return retval;
00894 }
00895 
00896 int LdapOperation::modify( const LdapDN &dn, const ModOps &ops )
00897 {
00898   Q_ASSERT( d->mConnection );
00899   LDAP *ld = (LDAP*) d->mConnection->handle();
00900 
00901   int msgid;
00902   LDAPMod **lmod = 0;
00903 
00904   LDAPControl **serverctrls = 0, **clientctrls = 0;
00905   createControls( &serverctrls, d->mServerCtrls );
00906   createControls( &serverctrls, d->mClientCtrls );
00907 
00908   for ( int i = 0; i < ops.count(); ++i ) {
00909     int mtype = 0;
00910     switch ( ops[i].type ) {
00911     case Mod_None:
00912       mtype = 0;
00913       break;
00914     case Mod_Add:
00915       mtype = LDAP_MOD_ADD;
00916       break;
00917     case Mod_Replace:
00918       mtype = LDAP_MOD_REPLACE;
00919       break;
00920     case Mod_Del:
00921       mtype = LDAP_MOD_DELETE;
00922       break;
00923     }
00924     addModOp( &lmod, mtype, ops[i].attr, 0 );
00925     for ( int j = 0; j < ops[i].values.count(); ++j ) {
00926       addModOp( &lmod, mtype, ops[i].attr, &ops[i].values[j] );
00927     }
00928   }
00929 
00930   int retval =
00931     ldap_modify_ext( ld, dn.toString().toUtf8().data(), lmod, serverctrls, clientctrls, &msgid );
00932 
00933   ldap_controls_free( serverctrls );
00934   ldap_controls_free( clientctrls );
00935   ldap_mods_free( lmod, 1 );
00936   if ( retval == 0 ) {
00937     retval = msgid;
00938   }
00939   return retval;
00940 }
00941 
00942 int LdapOperation::modify_s( const LdapDN &dn, const ModOps &ops )
00943 {
00944   Q_ASSERT( d->mConnection );
00945   LDAP *ld = (LDAP*) d->mConnection->handle();
00946 
00947   LDAPMod **lmod = 0;
00948 
00949   LDAPControl **serverctrls = 0, **clientctrls = 0;
00950   createControls( &serverctrls, d->mServerCtrls );
00951   createControls( &serverctrls, d->mClientCtrls );
00952 
00953   for ( int i = 0; i < ops.count(); ++i ) {
00954     int mtype = 0;
00955     switch ( ops[i].type ) {
00956     case Mod_None:
00957       mtype = 0;
00958       break;
00959     case Mod_Add:
00960       mtype = LDAP_MOD_ADD;
00961       break;
00962     case Mod_Replace:
00963       mtype = LDAP_MOD_REPLACE;
00964       break;
00965     case Mod_Del:
00966       mtype = LDAP_MOD_DELETE;
00967       break;
00968     }
00969     addModOp( &lmod, mtype, ops[i].attr, 0 );
00970     for ( int j = 0; j < ops[i].values.count(); ++j ) {
00971       addModOp( &lmod, mtype, ops[i].attr, &ops[i].values[j] );
00972     }
00973   }
00974 
00975   int retval =
00976     ldap_modify_ext_s( ld, dn.toString().toUtf8().data(), lmod, serverctrls, clientctrls );
00977 
00978   ldap_controls_free( serverctrls );
00979   ldap_controls_free( clientctrls );
00980   ldap_mods_free( lmod, 1 );
00981   return retval;
00982 }
00983 
00984 int LdapOperation::compare( const LdapDN &dn, const QString &attr, const QByteArray &value )
00985 {
00986   Q_ASSERT( d->mConnection );
00987   LDAP *ld = (LDAP*) d->mConnection->handle();
00988   int msgid;
00989 
00990   LDAPControl **serverctrls = 0, **clientctrls = 0;
00991   createControls( &serverctrls, d->mServerCtrls );
00992   createControls( &serverctrls, d->mClientCtrls );
00993 
00994   int vallen = value.size();
00995   BerValue *berval;
00996   berval = (BerValue *) malloc( sizeof( BerValue ) );
00997   berval -> bv_val = (char *) malloc( vallen );
00998   berval -> bv_len = vallen;
00999   memcpy( berval -> bv_val, value.data(), vallen );
01000 
01001   int retval = ldap_compare_ext( ld, dn.toString().toUtf8().data(), attr.toUtf8().data(), berval,
01002                                  serverctrls, clientctrls, &msgid );
01003 
01004   ber_bvfree( berval );
01005   ldap_controls_free( serverctrls );
01006   ldap_controls_free( clientctrls );
01007 
01008   if ( retval == 0 ) {
01009     retval = msgid;
01010   }
01011   return retval;
01012 }
01013 
01014 int LdapOperation::compare_s( const LdapDN &dn, const QString &attr, const QByteArray &value )
01015 {
01016   Q_ASSERT( d->mConnection );
01017   LDAP *ld = (LDAP*) d->mConnection->handle();
01018 
01019   LDAPControl **serverctrls = 0, **clientctrls = 0;
01020   createControls( &serverctrls, d->mServerCtrls );
01021   createControls( &serverctrls, d->mClientCtrls );
01022 
01023   int vallen = value.size();
01024   BerValue *berval;
01025   berval = (BerValue *) malloc( sizeof( BerValue ) );
01026   berval -> bv_val = (char *) malloc( vallen );
01027   berval -> bv_len = vallen;
01028   memcpy( berval -> bv_val, value.data(), vallen );
01029 
01030   int retval = ldap_compare_ext_s( ld, dn.toString().toUtf8().data(), attr.toUtf8().data(), berval,
01031                                    serverctrls, clientctrls );
01032 
01033   ber_bvfree( berval );
01034   ldap_controls_free( serverctrls );
01035   ldap_controls_free( clientctrls );
01036 
01037   return retval;
01038 }
01039 
01040 int LdapOperation::exop( const QString &oid, const QByteArray &data )
01041 {
01042   Q_ASSERT( d->mConnection );
01043 #if defined(HAVE_LDAP_EXTENDED_OPERATION) && defined(HAVE_LDAP_EXTENDED_OPERATION_PROTOTYPE)
01044   LDAP *ld = (LDAP*) d->mConnection->handle();
01045   int msgid;
01046 
01047   LDAPControl **serverctrls = 0, **clientctrls = 0;
01048   createControls( &serverctrls, d->mServerCtrls );
01049   createControls( &serverctrls, d->mClientCtrls );
01050 
01051   int vallen = data.size();
01052   BerValue *berval;
01053   berval = (BerValue *) malloc( sizeof( BerValue ) );
01054   berval -> bv_val = (char *) malloc( vallen );
01055   berval -> bv_len = vallen;
01056   memcpy( berval -> bv_val, data.data(), vallen );
01057 
01058   int retval = ldap_extended_operation( ld, oid.toUtf8().data(), berval,
01059                                         serverctrls, clientctrls, &msgid );
01060 
01061   ber_bvfree( berval );
01062   ldap_controls_free( serverctrls );
01063   ldap_controls_free( clientctrls );
01064 
01065   if ( retval == 0 ) {
01066     retval = msgid;
01067   }
01068   return retval;
01069 #else
01070   kError() << "Your LDAP client libraries don't support extended operations.";
01071   return -1;
01072 #endif
01073 }
01074 
01075 int LdapOperation::exop_s( const QString &oid, const QByteArray &data )
01076 {
01077 #if defined(HAVE_LDAP_EXTENDED_OPERATION) && defined(HAVE_LDAP_EXTENDED_OPERATION_PROTOTYPE)
01078   Q_ASSERT( d->mConnection );
01079   LDAP *ld = (LDAP*) d->mConnection->handle();
01080   BerValue *retdata;
01081   char *retoid;
01082 
01083   LDAPControl **serverctrls = 0, **clientctrls = 0;
01084   createControls( &serverctrls, d->mServerCtrls );
01085   createControls( &serverctrls, d->mClientCtrls );
01086 
01087   int vallen = data.size();
01088   BerValue *berval;
01089   berval = (BerValue *) malloc( sizeof( BerValue ) );
01090   berval -> bv_val = (char *) malloc( vallen );
01091   berval -> bv_len = vallen;
01092   memcpy( berval -> bv_val, data.data(), vallen );
01093 
01094   int retval = ldap_extended_operation_s( ld, oid.toUtf8().data(), berval,
01095                                           serverctrls, clientctrls, &retoid, &retdata );
01096 
01097   ber_bvfree( berval );
01098   ber_bvfree( retdata );
01099   free( retoid );
01100   ldap_controls_free( serverctrls );
01101   ldap_controls_free( clientctrls );
01102 
01103   return retval;
01104 #else
01105   kError() << "Your LDAP client libraries don't support extended operations.";
01106   return -1;
01107 #endif
01108 }
01109 
01110 int LdapOperation::abandon( int id )
01111 {
01112   Q_ASSERT( d->mConnection );
01113   LDAP *ld = (LDAP*) d->mConnection->handle();
01114 
01115   LDAPControl **serverctrls = 0, **clientctrls = 0;
01116   createControls( &serverctrls, d->mServerCtrls );
01117   createControls( &serverctrls, d->mClientCtrls );
01118 
01119   int retval = ldap_abandon_ext( ld, id, serverctrls, clientctrls );
01120 
01121   ldap_controls_free( serverctrls );
01122   ldap_controls_free( clientctrls );
01123 
01124   return retval;
01125 }
01126 
01127 int LdapOperation::waitForResult( int id, int msecs )
01128 {
01129   Q_ASSERT( d->mConnection );
01130   LDAP *ld = (LDAP*) d->mConnection->handle();
01131 
01132   LDAPMessage *msg;
01133   int rescode;
01134 
01135   QTime stopWatch;
01136   stopWatch.start();
01137   int attempt( 1 );
01138   int timeout( 0 );
01139 
01140   do {
01141     // Calculate the timeout value to use and assign it to a timeval structure
01142     // see man select (2) for details
01143     timeout = kldap_timeout_value( msecs, stopWatch.elapsed() );
01144     kDebug(5322) << "(" << id << "," << msecs
01145              << "): Waiting" << timeout 
01146              << "msecs for result. Attempt #" << attempt++;
01147     struct timeval tv;
01148     tv.tv_sec = timeout / 1000;
01149     tv.tv_usec = ( timeout % 1000 ) * 1000;
01150 
01151     // Wait for a result
01152     rescode = ldap_result( ld, id, 0, timeout < 0 ? 0 : &tv, &msg );
01153     if ( rescode == -1 ) {
01154       return -1;
01155     }
01156     // Act on the return code
01157     if ( rescode != 0 ) {
01158       // Some kind of result is available for processing
01159       return d->processResult( rescode, msg );
01160     }
01161   } while ( msecs == -1 || stopWatch.elapsed() < msecs );
01162 
01163   return 0; //timeout
01164 }
01165 
01166 #else
01167 
01168 int LdapOperation::bind( const QByteArray &creds, SASL_Callback_Proc *saslproc, void *data )
01169 {
01170   kError() << "LDAP support not compiled";
01171   return -1;
01172 }
01173 
01174 int LdapOperation::bind_s( SASL_Callback_Proc *saslproc, void *data )
01175 {
01176   kError() << "LDAP support not compiled";
01177   return -1;
01178 }
01179 
01180 int LdapOperation::search( const LdapDN &base, LdapUrl::Scope scope,
01181                            const QString &filter, const QStringList &attributes )
01182 {
01183   kError() << "LDAP support not compiled";
01184   return -1;
01185 }
01186 
01187 int LdapOperation::add( const LdapObject &object )
01188 {
01189   kError() << "LDAP support not compiled";
01190   return -1;
01191 }
01192 
01193 int LdapOperation::add_s( const LdapObject &object )
01194 {
01195   kError() << "LDAP support not compiled";
01196   return -1;
01197 }
01198 
01199 int LdapOperation::add( const LdapDN &dn, const ModOps &ops )
01200 {
01201   kError() << "LDAP support not compiled";
01202   return -1;
01203 }
01204 
01205 int LdapOperation::add_s( const LdapDN &dn, const ModOps &ops )
01206 {
01207   kError() << "LDAP support not compiled";
01208   return -1;
01209 }
01210                                 
01211 int LdapOperation::rename( const LdapDN &dn, const QString &newRdn,
01212                            const QString &newSuperior, bool deleteold )
01213 {
01214   kError() << "LDAP support not compiled";
01215   return -1;
01216 }
01217 
01218 int LdapOperation::rename_s( const LdapDN &dn, const QString &newRdn,
01219                              const QString &newSuperior, bool deleteold )
01220 {
01221   kError() << "LDAP support not compiled";
01222   return -1;
01223 }
01224 
01225 int LdapOperation::del( const LdapDN &dn )
01226 {
01227   kError() << "LDAP support not compiled";
01228   return -1;
01229 }
01230 
01231 int LdapOperation::del_s( const LdapDN &dn )
01232 {
01233   kError() << "LDAP support not compiled";
01234   return -1;
01235 }
01236 
01237 int LdapOperation::modify( const LdapDN &dn, const ModOps &ops )
01238 {
01239   kError() << "LDAP support not compiled";
01240   return -1;
01241 }
01242 
01243 int LdapOperation::modify_s( const LdapDN &dn, const ModOps &ops )
01244 {
01245   kError() << "LDAP support not compiled";
01246   return -1;
01247 }
01248 
01249 int LdapOperation::compare( const LdapDN &dn, const QString &attr, const QByteArray &value )
01250 {
01251   kError() << "LDAP support not compiled";
01252   return -1;
01253 }
01254 
01255 int LdapOperation::exop( const QString &oid, const QByteArray &data )
01256 {
01257   kError() << "LDAP support not compiled";
01258   return -1;
01259 }
01260 
01261 int LdapOperation::compare_s( const LdapDN &dn, const QString &attr, const QByteArray &value )
01262 {
01263   kError() << "LDAP support not compiled";
01264   return -1;
01265 }
01266 
01267 int LdapOperation::exop_s( const QString &oid, const QByteArray &data )
01268 {
01269   kError() << "LDAP support not compiled";
01270   return -1;
01271 }
01272 
01273 int LdapOperation::waitForResult( int id, int msecs )
01274 {
01275   kError() << "LDAP support not compiled";
01276   return -1;
01277 }
01278 
01279 int LdapOperation::abandon( int id )
01280 {
01281   kError() << "LDAP support not compiled";
01282   return -1;
01283 }
01284 
01285 #endif

KLDAP Library

Skip menu "KLDAP Library"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • kabc
  • kblog
  • kcal
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.5.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal