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