ldif.cpp

00001 /*
00002     This file is part of libkabc.
00003     Copyright (c) 2004 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 <kdebug.h>
00022 #include <kmdcodec.h>
00023 
00024 #include "ldif.h"
00025 
00026 using namespace KABC;
00027 
00028 LDIF::LDIF()
00029 {
00030   startParsing();
00031 }
00032 
00033 LDIF::~LDIF()
00034 {
00035 }
00036 
00037 QCString LDIF::assembleLine( const QString &fieldname, const QByteArray &value,
00038   uint linelen, bool url )
00039 {
00040   bool safe = false;
00041   bool isDn;
00042   QCString result;
00043   uint i;
00044 
00045   if ( url ) {
00046     result = fieldname.utf8() + ":< " + QCString( value.data(), value.size()+1 );
00047   } else {
00048     isDn = fieldname.lower() == "dn";
00049     //SAFE-INIT-CHAR
00050     if ( value.size() > 0 && value[0] > 0 && value[0] != '\n' &&
00051       value[0] != '\r' && value[0] != ':' && value[0] != '<' ) safe = true;
00052 
00053     //SAFE-CHAR
00054     if ( safe ) {
00055       for ( i=1; i < value.size(); i++ ) {
00056       //allow utf-8 in Distinguished Names
00057         if ( ( isDn && value[i] == 0 ) ||
00058              ( !isDn && value[i] <= 0 ) ||
00059              value[i] == '\r' || value[i] == '\n' ) {
00060           safe = false;
00061           break;
00062         }
00063       }
00064     }
00065 
00066     if ( value.size() == 0 ) safe = true;
00067 
00068     if( safe ) {
00069       result = fieldname.utf8() + ": " + QCString( value.data(), value.size()+1 );
00070     } else {
00071       result = fieldname.utf8() + ":: " + KCodecs::base64Encode( value, false );
00072     }
00073 
00074     if ( linelen > 0 ) {
00075       i = (fieldname.length()+2) > linelen ? fieldname.length()+2 : linelen;
00076       while ( i < result.length() ) {
00077         result.insert( i, "\n " );
00078         i += linelen+2;
00079       }
00080     }
00081   }
00082   return result;
00083 }
00084 
00085 QCString LDIF::assembleLine( const QString &fieldname, const QCString &value,
00086   uint linelen, bool url )
00087 {
00088   QCString ret;
00089   QByteArray tmp;
00090   uint valuelen = value.length();
00091   const char *data = value.data();
00092 
00093   tmp.setRawData( data, valuelen );
00094   ret = assembleLine( fieldname, tmp, linelen, url );
00095   tmp.resetRawData( data, valuelen );
00096   return ret;
00097 
00098 }
00099 
00100 QCString LDIF::assembleLine( const QString &fieldname, const QString &value,
00101   uint linelen, bool url )
00102 {
00103   return assembleLine( fieldname, value.utf8(), linelen, url );
00104 }
00105 
00106 bool LDIF::splitLine( const QCString &line, QString &fieldname, QByteArray &value )
00107 {
00108   int position;
00109   QByteArray tmp;
00110   int linelen;
00111   const char *data;
00112 
00113 //  kdDebug(5700) << "splitLine line: " << QString::fromUtf8(line) << endl;
00114 
00115   position = line.find( ":" );
00116   if ( position == -1 ) {
00117     // strange: we did not find a fieldname
00118     fieldname = "";
00119     QCString str;
00120     str = line.stripWhiteSpace();
00121     linelen = str.length();
00122     data = str.data();
00123     tmp.setRawData( data, linelen );
00124     value = tmp.copy();
00125     tmp.resetRawData( data, linelen );
00126 //    kdDebug(5700) << "value : " << value[0] << endl;
00127     return false;
00128   }
00129 
00130   linelen = line.length();
00131 
00132   if ( linelen > ( position + 1 ) && line[ position + 1 ] == ':' ) {
00133     // String is BASE64 encoded -> decode it now.
00134     fieldname = QString::fromUtf8(
00135       line.left( position ).stripWhiteSpace() );
00136     if ( linelen <= ( position + 3 ) ) {
00137       value.resize( 0 );
00138       return false;
00139     }
00140     data = &line.data()[ position + 3 ];
00141     tmp.setRawData( data, linelen - position - 3 );
00142     KCodecs::base64Decode( tmp, value );
00143     tmp.resetRawData( data, linelen - position - 3 );
00144     return false;
00145   }
00146 
00147   if ( linelen > ( position + 1 ) && line[ position + 1 ] == '<' ) {
00148     // String is an URL.
00149     fieldname = QString::fromUtf8(
00150       line.left( position ).stripWhiteSpace() );
00151     if ( linelen <= ( position + 3 ) ) {
00152       value.resize( 0 );
00153       return false;
00154     }
00155     data = &line.data()[ position + 3];
00156     tmp.setRawData( data, linelen - position - 3 );
00157     value = tmp.copy();
00158     tmp.resetRawData( data, linelen - position - 3 );
00159     return true;
00160   }
00161 
00162   fieldname = QString::fromUtf8(line.left( position ).stripWhiteSpace());
00163   if ( linelen <= ( position + 2 ) ) {
00164     value.resize( 0 );
00165     return false;
00166   }
00167   data = &line.data()[ position + 2 ];
00168   tmp.setRawData( data, linelen - position - 2 );
00169   value = tmp.copy();
00170   tmp.resetRawData( data, linelen - position - 2 );
00171   return false;
00172 }
00173 
00174 bool LDIF::splitControl( const QCString &line, QString &oid, bool &critical, 
00175   QByteArray &value )
00176 {
00177   QString tmp;
00178   critical = false;
00179   bool url = splitLine( line, tmp, value );
00180   
00181   kdDebug(5700) << "splitControl: value: " << QString::fromUtf8(value, value.size()) << endl;
00182   if ( tmp.isEmpty() ) {
00183     tmp = QString::fromUtf8( value, value.size() );
00184     value.resize( 0 );
00185   }
00186   if ( tmp.right( 4 ) == "true" ) {
00187     critical = true;
00188     tmp.truncate( tmp.length() - 5 );
00189   } else  if ( tmp.right( 5 ) == "false" ) {
00190     critical = false;
00191     tmp.truncate( tmp.length() - 6 );
00192   }
00193   oid = tmp;
00194   return url;
00195 }
00196 
00197 LDIF::ParseVal LDIF::processLine() 
00198 {
00199 
00200   if ( mIsComment ) return None;
00201 
00202   ParseVal retval = None;
00203   if ( mLastParseVal == EndEntry ) mEntryType = Entry_None;
00204 
00205   mUrl = splitLine( line, mAttr, mVal );
00206 
00207   QString attrLower = mAttr.lower();
00208 
00209   switch ( mEntryType ) {
00210     case Entry_None:
00211       if ( attrLower == "version" ) {
00212         if ( !mDn.isEmpty() ) retval = Err;
00213       } else if ( attrLower == "dn" ) {
00214         kdDebug(5700) << "ldapentry dn: " << QString::fromUtf8( mVal, mVal.size() ) << endl;
00215         mDn = QString::fromUtf8( mVal, mVal.size() );
00216         mModType = Mod_None;
00217         retval = NewEntry;
00218       } else if ( attrLower == "changetype" ) {
00219         if ( mDn.isEmpty() )
00220           retval = Err;
00221         else {
00222           QString tmpval = QString::fromUtf8( mVal, mVal.size() );
00223           kdDebug(5700) << "changetype: " << tmpval << endl;
00224           if ( tmpval == "add" ) mEntryType = Entry_Add;
00225           else if ( tmpval == "delete" ) mEntryType = Entry_Del;
00226           else if ( tmpval == "modrdn" || tmpval == "moddn" ) {
00227             mNewRdn = "";
00228             mNewSuperior = "";
00229             mDelOldRdn = true;
00230             mEntryType = Entry_Modrdn;
00231           }
00232           else if ( tmpval == "modify" ) mEntryType = Entry_Mod;
00233           else retval = Err;
00234         }
00235       } else if ( attrLower == "control" ) {
00236         mUrl = splitControl( QCString( mVal, mVal.size() + 1 ), mOid, mCritical, mVal );
00237         retval = Control;
00238       } else if ( !mAttr.isEmpty() && mVal.size() > 0 ) {
00239         mEntryType = Entry_Add;
00240         retval = Item;
00241       }
00242       break;
00243     case Entry_Add:
00244       if ( mAttr.isEmpty() && mVal.size() == 0 )
00245         retval = EndEntry;
00246       else
00247         retval = Item;
00248       break;
00249     case Entry_Del:
00250       if ( mAttr.isEmpty() && mVal.size() == 0 )
00251         retval = EndEntry;
00252       else
00253         retval = Err;
00254       break;
00255     case Entry_Mod:
00256       if ( mModType == Mod_None ) {
00257         kdDebug(5700) << "kio_ldap: new modtype " << mAttr << endl;
00258         if ( mAttr.isEmpty() && mVal.size() == 0 ) {
00259           retval = EndEntry;
00260         } else if ( attrLower == "add" ) {
00261           mModType = Mod_Add;
00262         } else if ( attrLower == "replace" ) {
00263           mModType = Mod_Replace;
00264           mAttr = QString::fromUtf8( mVal, mVal.size() );
00265           mVal.resize( 0 );
00266           retval = Item;
00267         } else if ( attrLower == "delete" ) {
00268           mModType = Mod_Del;
00269           mAttr = QString::fromUtf8( mVal, mVal.size() );
00270           mVal.resize( 0 );
00271           retval = Item;
00272         } else {
00273           retval = Err;
00274         }
00275       } else {
00276         if ( mAttr.isEmpty() ) {
00277           if ( QString::fromUtf8( mVal, mVal.size() ) == "-" ) {
00278             mModType = Mod_None;
00279           } else if ( mVal.size() == 0 ) {
00280             retval = EndEntry;
00281           } else
00282             retval = Err;
00283         } else
00284           retval = Item;
00285       }
00286       break;
00287     case Entry_Modrdn:
00288       if ( mAttr.isEmpty() && mVal.size() == 0 )
00289         retval = EndEntry;
00290       else if ( attrLower == "newrdn" )
00291         mNewRdn = QString::fromUtf8( mVal, mVal.size() );
00292       else if ( attrLower == "newsuperior" )
00293         mNewSuperior = QString::fromUtf8( mVal, mVal.size() );
00294       else if ( attrLower == "deleteoldrdn" ) {
00295         if ( mVal.size() > 0 && mVal[0] == '0' )
00296           mDelOldRdn = false;
00297         else if ( mVal.size() > 0 && mVal[0] == '1' )
00298           mDelOldRdn = true;
00299         else
00300           retval = Err;
00301       } else
00302         retval = Err;
00303       break;
00304   }
00305   return retval;
00306 }
00307 
00308 LDIF::ParseVal LDIF::nextItem()
00309 {
00310   ParseVal retval = None;
00311   char c=0;
00312 
00313   while( retval == None ) {
00314     if ( mPos < mLdif.size() ) {
00315       c = mLdif[mPos];
00316       mPos++;
00317       if ( mIsNewLine && c == '\r' ) continue; //handle \n\r line end
00318       if ( mIsNewLine && ( c == ' ' || c == '\t' ) ) { //line folding
00319         mIsNewLine = false;
00320         continue;
00321       }
00322       if ( mIsNewLine ) {
00323         mIsNewLine = false;
00324         retval = processLine();
00325         mLastParseVal = retval;
00326         line.resize( 0 );
00327         mIsComment = ( c == '#' );
00328       }
00329       if ( c == '\n' || c == '\r' ) {
00330         mLineNo++;
00331         mIsNewLine = true;
00332         continue;
00333       }
00334     } else {
00335       retval = MoreData;
00336       break;
00337     }
00338 
00339     if ( !mIsComment ) line += c;
00340   }
00341   return retval;
00342 }
00343 
00344 void LDIF::endLDIF()
00345 {
00346   QByteArray tmp( 3 );
00347   tmp[ 0 ] = '\n';
00348   tmp[ 1 ] = '\n';
00349   tmp[ 2 ] = '\n';
00350   mLdif = tmp;
00351   mPos = 0;
00352 }
00353 
00354 void LDIF::startParsing()
00355 {
00356   mPos = mLineNo = 0;
00357   mDelOldRdn = false;
00358   mEntryType = Entry_None;
00359   mModType = Mod_None;
00360   mDn = mNewRdn = mNewSuperior = "";
00361   line = "";
00362   mIsNewLine = false;
00363   mIsComment = false;
00364   mLastParseVal = None;
00365 }
KDE Home | KDE Accessibility Home | Description of Access Keys