ldif.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       ldif.cc
00003 ///             Routines for reading and writing LDAP LDIF data.
00004 ///
00005 
00006 /*
00007     Copyright (C) 2005-2009, Net Direct Inc. (http://www.netdirect.ca/)
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018     See the GNU General Public License in the COPYING file at the
00019     root directory of this project for more details.
00020 */
00021 
00022 #include "ldif.h"
00023 #include "record.h"
00024 #include "r_contact.h"
00025 #include "base64.h"
00026 #include <stdexcept>
00027 #include <iostream>
00028 #include <iomanip>
00029 #include <string.h>
00030 
00031 #define __DEBUG_MODE__
00032 #include "debug.h"
00033 
00034 namespace Barry {
00035 
00036 const ContactLdif::NameToFunc ContactLdif::FieldMap[] = {
00037         { "Email", "Email address",
00038                 &ContactLdif::Email, &ContactLdif::SetEmail },
00039         { "Phone", "Phone number",
00040                 &ContactLdif::Phone, &ContactLdif::SetPhone },
00041         { "Fax", "Fax number",
00042                 &ContactLdif::Fax, &ContactLdif::SetFax },
00043         { "WorkPhone", "Work phone number",
00044                 &ContactLdif::WorkPhone, &ContactLdif::SetWorkPhone },
00045         { "HomePhone", "Home phone number",
00046                 &ContactLdif::HomePhone, &ContactLdif::SetHomePhone },
00047         { "MobilePhone", "Mobile phone number",
00048                 &ContactLdif::MobilePhone, &ContactLdif::SetMobilePhone },
00049         { "Pager", "Pager number",
00050                 &ContactLdif::Pager, &ContactLdif::SetPager },
00051         { "PIN", "PIN",
00052                 &ContactLdif::PIN, &ContactLdif::SetPIN },
00053         { "FirstName", "First name",
00054                 &ContactLdif::FirstName, &ContactLdif::SetFirstName },
00055         { "LastName", "Last name",
00056                 &ContactLdif::LastName, &ContactLdif::SetLastName },
00057         { "Company", "Company name",
00058                 &ContactLdif::Company, &ContactLdif::SetCompany },
00059         { "DefaultCommunicationsMethod", "Default communications method",
00060                 &ContactLdif::DefaultCommunicationsMethod, &ContactLdif::SetDefaultCommunicationsMethod },
00061         { "Address1", "Address, line 1",
00062                 &ContactLdif::Address1, &ContactLdif::SetAddress1 },
00063         { "Address2", "Address, line 2",
00064                 &ContactLdif::Address2, &ContactLdif::SetAddress2 },
00065         { "Address3", "Address, line 3",
00066                 &ContactLdif::Address3, &ContactLdif::SetAddress3 },
00067         { "City", "City",
00068                 &ContactLdif::City, &ContactLdif::SetCity },
00069         { "Province", "Province / State",
00070                 &ContactLdif::Province, &ContactLdif::SetProvince },
00071         { "PostalCode", "Postal / ZIP code",
00072                 &ContactLdif::PostalCode, &ContactLdif::SetPostalCode },
00073         { "Country", "Country",
00074                 &ContactLdif::Country, &ContactLdif::SetCountry },
00075         { "JobTitle", "Job Title",
00076                 &ContactLdif::JobTitle, &ContactLdif::SetJobTitle },
00077         { "PublicKey", "Public key",
00078                 &ContactLdif::PublicKey, &ContactLdif::SetPublicKey },
00079         { "Notes", "Notes",
00080                 &ContactLdif::Notes, &ContactLdif::SetNotes },
00081         { "PostalAddress", "Mailing address (includes address lines, city, province, country, and postal code)",
00082                 &ContactLdif::PostalAddress, &ContactLdif::SetPostalAddress },
00083         { "FullName", "First + Last names",
00084                 &ContactLdif::FullName, &ContactLdif::SetFullName },
00085         { "FQDN", "Fully qualified domain name",
00086                 &ContactLdif::FQDN, &ContactLdif::SetFQDN },
00087         { 0, 0, 0 }
00088 };
00089 
00090 
00091 bool ContactLdif::LdifAttribute::operator<(const LdifAttribute &other) const
00092 {
00093         // the dn attribute always comes first in LDIF output
00094         if( name == "dn" ) {
00095                 if( other.name == "dn" )
00096                         return false;   // both dn, so equal
00097                 return true;
00098         }
00099         else if( other.name == "dn" )
00100                 return false;
00101 
00102         return (order < other.order && name != other.name) ||
00103                 (order == other.order && name < other.name);
00104 }
00105 
00106 bool ContactLdif::LdifAttribute::operator==(const LdifAttribute &other) const
00107 {
00108         return name == other.name;
00109 }
00110 
00111 
00112 ///////////////////////////////////////////////////////////////////////////////
00113 // ContactLdif class
00114 
00115 ContactLdif::ContactLdif(const std::string &baseDN)
00116         : m_baseDN(baseDN)
00117 {
00118         // setup some sane defaults
00119         Map("mail", &ContactLdif::Email, &ContactLdif::SetEmail);
00120         Map("facsimileTelephoneNumber", &ContactLdif::Fax, &ContactLdif::SetFax);
00121         Map("telephoneNumber", &ContactLdif::WorkPhone, &ContactLdif::SetWorkPhone);
00122         Map("homePhone", &ContactLdif::HomePhone, &ContactLdif::SetHomePhone);
00123         Map("mobile", &ContactLdif::MobilePhone, &ContactLdif::SetMobilePhone);
00124         Map("pager", &ContactLdif::Pager, &ContactLdif::SetPager);
00125         Map("l", &ContactLdif::City, &ContactLdif::SetCity);
00126         Map("st", &ContactLdif::Province, &ContactLdif::SetProvince);
00127         Map("postalCode", &ContactLdif::PostalCode, &ContactLdif::SetPostalCode);
00128         Map("o", &ContactLdif::Company, &ContactLdif::SetCompany);
00129         Map("c", &ContactLdif::Country, &ContactLdif::SetCountry);
00130         SetObjectClass("c", "country");
00131 
00132         Map("title", &ContactLdif::JobTitle, &ContactLdif::SetJobTitle);
00133         Map("dn", &ContactLdif::FQDN, &ContactLdif::SetFQDN);
00134         Map("displayName", &ContactLdif::FullName, &ContactLdif::SetFullName);
00135         Map("cn", &ContactLdif::FullName, &ContactLdif::SetFullName);
00136         Map("sn", &ContactLdif::LastName, &ContactLdif::SetLastName);
00137         Map("givenName", &ContactLdif::FirstName, &ContactLdif::SetFirstName);
00138         Map("street", &ContactLdif::Address1, &ContactLdif::SetAddress1);
00139         Map("postalAddress", &ContactLdif::PostalAddress, &ContactLdif::SetPostalAddress);
00140         Map("note", &ContactLdif::Notes, &ContactLdif::SetNotes);
00141 
00142         // add heuristics hooks
00143         Hook("cn", &m_cn);
00144         Hook("displayName", &m_displayName);
00145         Hook("sn", &m_sn);
00146         Hook("givenName", &m_givenName);
00147 
00148         // set default DN attribute
00149         SetDNAttr("cn");
00150 }
00151 
00152 ContactLdif::~ContactLdif()
00153 {
00154 }
00155 
00156 void ContactLdif::DoWrite(Barry::Contact &con,
00157                           const std::string &attr,
00158                           const std::string &data)
00159 {
00160         // valid?
00161         if( attr.size() == 0 || data.size() == 0 )
00162                 return;
00163 
00164         // now have attr/data pair, check hooks:
00165         HookMapType::iterator hook = m_hookMap.find(attr);
00166         if( hook != m_hookMap.end() ) {
00167                 *(hook->second) = data;
00168         }
00169 
00170         // run according to map
00171         AccessMapType::iterator acc = m_map.find(attr);
00172         if( acc != m_map.end() ) {
00173                 (this->*(acc->second.write))(con, data);
00174         }
00175 }
00176 
00177 void ContactLdif::Hook(const std::string &ldifname, std::string *var)
00178 {
00179         m_hookMap[ldifname] = var;
00180 }
00181 
00182 const ContactLdif::NameToFunc*
00183 ContactLdif::GetField(const std::string &fieldname) const
00184 {
00185         for( const NameToFunc *n = FieldMap; n->name; n++ ) {
00186                 if( fieldname == n->name )
00187                         return n;
00188         }
00189         return 0;
00190 }
00191 
00192 std::string ContactLdif::GetFieldReadName(GetFunctionType read) const
00193 {
00194         for( const NameToFunc *n = FieldMap; n->name; n++ ) {
00195                 if( read == n->read )
00196                         return n->name;
00197         }
00198         return "<unknown>";
00199 }
00200 
00201 std::string ContactLdif::GetFieldWriteName(SetFunctionType write) const
00202 {
00203         for( const NameToFunc *n = FieldMap; n->name; n++ ) {
00204                 if( write == n->write )
00205                         return n->name;
00206         }
00207         return "<unknown>";
00208 }
00209 
00210 bool ContactLdif::Map(const LdifAttribute &ldifname,
00211                       const std::string &readField,
00212                       const std::string &writeField)
00213 {
00214         const NameToFunc *read = GetField(readField);
00215         const NameToFunc *write = GetField(writeField);
00216         if( !read || !write )
00217                 return false;
00218         Map(ldifname, read->read, write->write);
00219         return true;
00220 }
00221 
00222 void ContactLdif::Map(const LdifAttribute &ldifname,
00223                       GetFunctionType read,
00224                       SetFunctionType write)
00225 {
00226         m_map[ldifname] = AccessPair(read, write);
00227 }
00228 
00229 void ContactLdif::Unmap(const LdifAttribute &ldifname)
00230 {
00231         m_map.erase(ldifname);
00232 }
00233 
00234 //
00235 // SetDNAttr
00236 //
00237 /// Sets the LDIF attribute name to use when constructing the FQDN.
00238 /// The FQDN field will take this name, and combine it with the
00239 /// baseDN from the constructor to produce a FQDN for the record.
00240 ///
00241 bool ContactLdif::SetDNAttr(const LdifAttribute &name)
00242 {
00243         // try to find the attribute in the map
00244         AccessMapType::iterator i = m_map.find(name);
00245         if( i == m_map.end() )
00246                 return false;
00247 
00248         m_dnAttr = name;
00249         return true;
00250 }
00251 
00252 bool ContactLdif::SetObjectClass(const LdifAttribute &name,
00253                                  const std::string &objectClass)
00254 {
00255         AccessMapType::iterator i = m_map.find(name);
00256         if( i == m_map.end() )
00257                 return false;
00258 
00259         LdifAttribute key = i->first;
00260         AccessPair pair = i->second;
00261         m_map.erase(key);
00262         key.objectClass = objectClass;
00263         m_map[key] = pair;
00264         return true;
00265 }
00266 
00267 bool ContactLdif::SetObjectOrder(const LdifAttribute &name, int order)
00268 {
00269         AccessMapType::iterator i = m_map.find(name);
00270         if( i == m_map.end() )
00271                 return false;
00272 
00273         LdifAttribute key = i->first;
00274         AccessPair pair = i->second;
00275         m_map.erase(key);
00276         key.order = order;
00277         m_map[key] = pair;
00278         return true;
00279 }
00280 
00281 
00282 std::string ContactLdif::Email(const Barry::Contact &con) const
00283 {
00284         return con.GetEmail(m_emailIndex++);
00285 }
00286 
00287 std::string ContactLdif::Phone(const Barry::Contact &con) const
00288 {
00289         return con.Phone;
00290 }
00291 
00292 std::string ContactLdif::Fax(const Barry::Contact &con) const
00293 {
00294         return con.Fax;
00295 }
00296 
00297 std::string ContactLdif::WorkPhone(const Barry::Contact &con) const
00298 {
00299         return con.WorkPhone;
00300 }
00301 
00302 std::string ContactLdif::HomePhone(const Barry::Contact &con) const
00303 {
00304         return con.HomePhone;
00305 }
00306 
00307 std::string ContactLdif::MobilePhone(const Barry::Contact &con) const
00308 {
00309         return con.MobilePhone;
00310 }
00311 
00312 std::string ContactLdif::Pager(const Barry::Contact &con) const
00313 {
00314         return con.Pager;
00315 }
00316 
00317 std::string ContactLdif::PIN(const Barry::Contact &con) const
00318 {
00319         return con.PIN;
00320 }
00321 
00322 std::string ContactLdif::FirstName(const Barry::Contact &con) const
00323 {
00324         return con.FirstName;
00325 }
00326 
00327 std::string ContactLdif::LastName(const Barry::Contact &con) const
00328 {
00329         return con.LastName;
00330 }
00331 
00332 std::string ContactLdif::Company(const Barry::Contact &con) const
00333 {
00334         return con.Company;
00335 }
00336 
00337 std::string ContactLdif::DefaultCommunicationsMethod(const Barry::Contact &con) const
00338 {
00339         return con.DefaultCommunicationsMethod;
00340 }
00341 
00342 std::string ContactLdif::Address1(const Barry::Contact &con) const
00343 {
00344         return con.WorkAddress.Address1;
00345 }
00346 
00347 std::string ContactLdif::Address2(const Barry::Contact &con) const
00348 {
00349         return con.WorkAddress.Address2;
00350 }
00351 
00352 std::string ContactLdif::Address3(const Barry::Contact &con) const
00353 {
00354         return con.WorkAddress.Address3;
00355 }
00356 
00357 std::string ContactLdif::City(const Barry::Contact &con) const
00358 {
00359         return con.WorkAddress.City;
00360 }
00361 
00362 std::string ContactLdif::Province(const Barry::Contact &con) const
00363 {
00364         return con.WorkAddress.Province;
00365 }
00366 
00367 std::string ContactLdif::PostalCode(const Barry::Contact &con) const
00368 {
00369         return con.WorkAddress.PostalCode;
00370 }
00371 
00372 std::string ContactLdif::Country(const Barry::Contact &con) const
00373 {
00374         return con.WorkAddress.Country;
00375 }
00376 
00377 std::string ContactLdif::JobTitle(const Barry::Contact &con) const
00378 {
00379         return con.JobTitle;
00380 }
00381 
00382 std::string ContactLdif::PublicKey(const Barry::Contact &con) const
00383 {
00384         return con.PublicKey;
00385 }
00386 
00387 std::string ContactLdif::Notes(const Barry::Contact &con) const
00388 {
00389         return con.Notes;
00390 }
00391 
00392 std::string ContactLdif::PostalAddress(const Barry::Contact &con) const
00393 {
00394         return con.WorkAddress.GetLabel();
00395 }
00396 
00397 std::string ContactLdif::FullName(const Barry::Contact &con) const
00398 {
00399         return con.GetFullName();
00400 }
00401 
00402 std::string ContactLdif::FQDN(const Barry::Contact &con) const
00403 {
00404         std::string FQDN = m_dnAttr.name;
00405         FQDN += "=";
00406 
00407         AccessMapType::const_iterator i = m_map.find(m_dnAttr);
00408         if( i != m_map.end() ) {
00409                 FQDN += (this->*(i->second.read))(con);
00410         }
00411         else {
00412                 FQDN += "unknown";
00413         }
00414 
00415         FQDN += ",";
00416         FQDN += m_baseDN;
00417         return FQDN;
00418 }
00419 
00420 bool ContactLdif::IsArrayFunc(GetFunctionType getf) const
00421 {
00422         // Currently, only the Email getter has array data
00423         if( getf == &ContactLdif::Email )
00424                 return true;
00425         return false;
00426 }
00427 
00428 void ContactLdif::ClearArrayState() const
00429 {
00430         m_emailIndex = 0;
00431 }
00432 
00433 void ContactLdif::SetEmail(Barry::Contact &con, const std::string &val) const
00434 {
00435         con.EmailAddresses.push_back(val);
00436 }
00437 
00438 void ContactLdif::SetPhone(Barry::Contact &con, const std::string &val) const
00439 {
00440         con.Phone = val;
00441 }
00442 
00443 void ContactLdif::SetFax(Barry::Contact &con, const std::string &val) const
00444 {
00445         con.Fax = val;
00446 }
00447 
00448 void ContactLdif::SetWorkPhone(Barry::Contact &con, const std::string &val) const
00449 {
00450         con.WorkPhone = val;
00451 }
00452 
00453 void ContactLdif::SetHomePhone(Barry::Contact &con, const std::string &val) const
00454 {
00455         con.HomePhone = val;
00456 }
00457 
00458 void ContactLdif::SetMobilePhone(Barry::Contact &con, const std::string &val) const
00459 {
00460         con.MobilePhone = val;
00461 }
00462 
00463 void ContactLdif::SetPager(Barry::Contact &con, const std::string &val) const
00464 {
00465         con.Pager = val;
00466 }
00467 
00468 void ContactLdif::SetPIN(Barry::Contact &con, const std::string &val) const
00469 {
00470         con.PIN = val;
00471 }
00472 
00473 void ContactLdif::SetFirstName(Barry::Contact &con, const std::string &val) const
00474 {
00475         con.FirstName = val;
00476 }
00477 
00478 void ContactLdif::SetLastName(Barry::Contact &con, const std::string &val) const
00479 {
00480         con.LastName = val;
00481 }
00482 
00483 void ContactLdif::SetCompany(Barry::Contact &con, const std::string &val) const
00484 {
00485         con.Company = val;
00486 }
00487 
00488 void ContactLdif::SetDefaultCommunicationsMethod(Barry::Contact &con, const std::string &val) const
00489 {
00490         con.DefaultCommunicationsMethod = val;
00491 }
00492 
00493 void ContactLdif::SetAddress1(Barry::Contact &con, const std::string &val) const
00494 {
00495         con.WorkAddress.Address1 = val;
00496 }
00497 
00498 void ContactLdif::SetAddress2(Barry::Contact &con, const std::string &val) const
00499 {
00500         con.WorkAddress.Address2 = val;
00501 }
00502 
00503 void ContactLdif::SetAddress3(Barry::Contact &con, const std::string &val) const
00504 {
00505         con.WorkAddress.Address3 = val;
00506 }
00507 
00508 void ContactLdif::SetCity(Barry::Contact &con, const std::string &val) const
00509 {
00510         con.WorkAddress.City = val;
00511 }
00512 
00513 void ContactLdif::SetProvince(Barry::Contact &con, const std::string &val) const
00514 {
00515         con.WorkAddress.Province = val;
00516 }
00517 
00518 void ContactLdif::SetPostalCode(Barry::Contact &con, const std::string &val) const
00519 {
00520         con.WorkAddress.PostalCode = val;
00521 }
00522 
00523 void ContactLdif::SetCountry(Barry::Contact &con, const std::string &val) const
00524 {
00525         con.WorkAddress.Country = val;
00526 }
00527 
00528 void ContactLdif::SetJobTitle(Barry::Contact &con, const std::string &val) const
00529 {
00530         con.JobTitle = val;
00531 }
00532 
00533 void ContactLdif::SetPublicKey(Barry::Contact &con, const std::string &val) const
00534 {
00535         con.PublicKey = val;
00536 }
00537 
00538 void ContactLdif::SetNotes(Barry::Contact &con, const std::string &val) const
00539 {
00540         con.Notes = val;
00541 }
00542 
00543 void ContactLdif::SetPostalAddress(Barry::Contact &con, const std::string &val) const
00544 {
00545         // fixme;
00546 //      throw std::runtime_error("SetPostalAddress() not implemented");
00547 //      std::cout << "SetPostalAddress() not implemented: " << val << std::endl;
00548 }
00549 
00550 void ContactLdif::SetFullName(Barry::Contact &con, const std::string &val) const
00551 {
00552         std::string first, last;
00553         Contact::SplitName(val, first, last);
00554         con.FirstName = first;
00555         con.LastName = last;
00556 }
00557 
00558 void ContactLdif::SetFQDN(Barry::Contact &con, const std::string &val) const
00559 {
00560         throw std::runtime_error("not implemented");
00561 }
00562 
00563 
00564 void ContactLdif::ClearHeuristics()
00565 {
00566         m_cn.clear();
00567         m_displayName.clear();
00568         m_sn.clear();
00569         m_givenName.clear();
00570 }
00571 
00572 bool ContactLdif::RunHeuristics(Barry::Contact &con)
00573 {
00574         // start fresh
00575         con.LastName.clear();
00576         con.FirstName.clear();
00577 
00578         // find the best match for name... prefer sn/givenName if available
00579         if( m_sn.size() ) {
00580                 con.LastName = m_sn;
00581         }
00582         if( m_givenName.size() ) {
00583                 con.FirstName = m_givenName;
00584         }
00585 
00586         if( !con.LastName.size() || !con.FirstName.size() ) {
00587                 std::string first, last;
00588 
00589                 // still don't have a complete name, check cn first
00590                 if( m_cn.size() ) {
00591                         Contact::SplitName(m_cn, first, last);
00592                         if( !con.LastName.size() && last.size() )
00593                                 con.LastName = last;
00594                         if( !con.FirstName.size() && first.size() )
00595                                 con.FirstName = first;
00596                 }
00597 
00598                 // displayName is last chance
00599                 if( m_displayName.size() ) {
00600                         Contact::SplitName(m_displayName, first, last);
00601                         if( !con.LastName.size() && last.size() )
00602                                 con.LastName = last;
00603                         if( !con.FirstName.size() && first.size() )
00604                                 con.FirstName = first;
00605                 }
00606         }
00607 
00608         return con.LastName.size() && con.FirstName.size();
00609 }
00610 
00611 
00612 //
00613 // DumpLdif
00614 //
00615 /// Output contact data to os in LDAP LDIF format.
00616 ///
00617 void ContactLdif::DumpLdif(std::ostream &os,
00618                        const Barry::Contact &con) const
00619 {
00620         // start fresh
00621         ClearArrayState();
00622 
00623         // setup stream state
00624         std::ios::fmtflags oldflags = os.setf(std::ios::left);
00625         char fill = os.fill(' ');
00626 
00627         if( FirstName(con).size() == 0 && LastName(con).size() == 0 )
00628                 return;                 // nothing to do
00629 
00630         os << "# Contact 0x" << std::hex << con.GetID() << ", "
00631                 << FullName(con) << "\n";
00632 
00633         // cycle through the map
00634         for(    AccessMapType::const_iterator b = m_map.begin();
00635                 b != m_map.end();
00636                 ++b )
00637         {
00638                 // print only fields with data
00639                 std::string field;
00640 
00641                 do {
00642                         field = (this->*(b->second.read))(con);
00643                         if( field.size() ) {
00644                                 os << b->first.name << MakeLdifData(field) << "\n";
00645                                 if( b->first.objectClass.size() )
00646                                         os << "objectClass: " << b->first.objectClass << "\n";
00647                         }
00648                 } while( IsArrayFunc(b->second.read) && field.size() );
00649         }
00650 
00651         os << "objectClass: inetOrgPerson\n";
00652 
00653         // last line must be empty
00654         os << "\n";
00655 
00656         // cleanup the stream
00657         os.flags(oldflags);
00658         os.fill(fill);
00659 }
00660 
00661 bool ContactLdif::ReadLdif(std::istream &is, Barry::Contact &con)
00662 {
00663         std::string line;
00664 
00665         // start fresh
00666         con.Clear();
00667         ClearHeuristics();
00668 
00669         // search for beginning dn: line
00670         bool found = false;
00671         while( std::getline(is, line) ) {
00672                 if( strncmp(line.c_str(), "dn: ", 4) == 0 ) {
00673                         found = true;
00674                         break;
00675                 }
00676         }
00677         if( !found )
00678                 return false;
00679 
00680         // storage for various name styles
00681         std::string coded, decode, attr, data;
00682         bool b64field = false;
00683 
00684         // read ldif lines until empty line is found
00685         while( getline(is, line) && line.size() ) {
00686 
00687                 if( b64field ) {
00688                         // processing a base64 encoded field
00689                         if( line[0] == ' ' ) {
00690                                 coded += "\n";
00691                                 coded += line;
00692                                 continue;
00693                         }
00694                         else {
00695                                 // end of base64 block... ignore errors,
00696                                 // and attempt to save everything decodable...
00697                                 // the LDAP server sometimes returns incomplete
00698                                 // base64 encoding, but otherwise the data is fine
00699                                 base64_decode(coded, decode);
00700                                 DoWrite(con, attr, decode);
00701                                 coded.clear();
00702                                 b64field = false;
00703                         }
00704                         // fall through to process new line
00705                 }
00706 
00707 
00708                 // split into attribute / data
00709                 std::string::size_type delim = line.find(':'), dstart;
00710                 if( delim == std::string::npos )
00711                         continue;
00712 
00713                 attr.assign(line, 0, delim);
00714                 dstart = delim + 1;
00715                 while( line[dstart] == ' ' || line[dstart] == ':' )
00716                         dstart++;
00717                 data = line.substr(dstart);
00718 
00719                 // is this data base64 encoded?
00720                 if( line[delim + 1] == ':' ) {
00721                         coded = data;
00722                         b64field = true;
00723                         continue;
00724                 }
00725 
00726                 DoWrite(con, attr, data);
00727         }
00728 
00729         if( b64field ) {
00730                 // clean up base64 decoding... ignore errors, see above comment
00731                 base64_decode(coded, decode);
00732                 DoWrite(con, attr, decode);
00733                 coded.clear();
00734                 b64field = false;
00735         }
00736 
00737         return RunHeuristics(con);
00738 }
00739 
00740 void ContactLdif::DumpMap(std::ostream &os) const
00741 {
00742         std::ios::fmtflags oldflags = os.setf(std::ios::left);
00743         char fill = os.fill(' ');
00744 
00745         os << "ContactLdif Mapping:\n";
00746 
00747         // cycle through the map
00748         for(    AccessMapType::const_iterator b = m_map.begin();
00749                 b != m_map.end();
00750                 ++b )
00751         {
00752                 os << "   " << std::left << std::setw(20) << b->first.name
00753                    << "->  " << GetFieldReadName(b->second.read)
00754                    << " / " << GetFieldWriteName(b->second.write) << "\n";
00755 
00756                 // find read/write names
00757 
00758                 if( b->first.objectClass.size() ) {
00759                         os << "   " << std::setw(20) << " "
00760                            << "objectClass: " << b->first.objectClass << "\n";
00761                 }
00762         }
00763 
00764         os << "   >>> DN attribute: " << m_dnAttr.name << "\n";
00765 
00766         // cleanup the stream
00767         os.flags(oldflags);
00768         os.fill(fill);
00769 }
00770 
00771 std::string ContactLdif::MakeLdifData(const std::string &str)
00772 {
00773         std::string data = ":";
00774 
00775         if( NeedsEncoding(str) ) {
00776                 std::string b64;
00777                 base64_encode(str, b64);
00778 
00779                 data += ": ";
00780                 data += b64;
00781         }
00782         else {
00783                 data += " ";
00784                 data += str;
00785         }
00786 
00787         return data;
00788 }
00789 
00790 //
00791 // RFC 2849
00792 //
00793 // Must not contain:
00794 //      0x00 (NUL), 0x0a (LF), 0x0d (CR), or anything greater than 0x7f
00795 //
00796 // First char must meet above criteria, plus must not be:
00797 //      0x20 (SPACE), 0x3a (colon), 0x3c ('<')
00798 //
00799 bool ContactLdif::NeedsEncoding(const std::string &str)
00800 {
00801         for( std::string::size_type i = 0; i < str.size(); i++ ) {
00802                 unsigned char c = str[i];
00803 
00804                 switch( c )
00805                 {
00806                 case 0x00:
00807                 case 0x0a:
00808                 case 0x0d:
00809                         return true;
00810 
00811                 case 0x20:
00812                 case 0x3a:
00813                 case 0x3c:
00814                         if( i == 0 )
00815                                 return true;
00816                 }
00817 
00818                 if( c > 0x7f )
00819                         return true;
00820         }
00821         return false;
00822 }
00823 
00824 } // namespace Barry
00825 

Generated on Mon Jan 12 10:51:12 2009 for Barry by  doxygen 1.5.7.1