Logo Search packages:      
Sourcecode: addresses-for-gnustep version File versions  Download package

ADVCFConverter.m

// ADVCFConverter.m (this is -*- ObjC -*-)
// 
// \author: Björn Giesler <giesler@ira.uka.de>
// 
// Address Book Framework for GNUstep
// 
// $Author: bjoern $
// $Locker:  $
// $Revision: 1.1.1.1 $
// $Date: 2004/02/14 18:00:02 $

/* system includes */
/* (none) */

/* my includes */
#include "ADVCFConverter.h"
#include "ADPerson.h"
#include "ADGlobals.h"
#include "ADImageLoading.h"
#include "ADMultiValue.h"

@interface NSString(QuotedPrintable)
- (unsigned long) hexLongValue;
- (NSString*) stringByQuotedPrintableDecoding;
- (NSString*) stringByQuotedPrintableEncoding;
@end

@implementation NSString(QuotedPrintable)
- (unsigned long) hexLongValue
{
  unsigned long val;
  NSString *str;
  NSString *hexchars;
  int i;

  val = 0;
  str = [[self stringByTrimmingCharactersInSet:
             [NSCharacterSet whitespaceCharacterSet]]
        lowercaseString];
  hexchars = @"0123456789abcdef";

  for(i=0; i<[str length]; i++)
    {
      NSRange r;
      NSString *substr;

      r = NSMakeRange(i, 1);
      substr = [str substringWithRange: r];
      r = [hexchars rangeOfString: substr];
      if(r.location == NSNotFound)
      [NSException raise: NSGenericException
                 format: @"\"%@\"[%d] not a hex char", str, i];
      val <<= 4;
      val |= r.location;
    }

  return val;
}

- (NSString*) stringByQuotedPrintableDecoding
{
  int i;
  NSMutableString *str;

  str = [NSMutableString stringWithCapacity: [self length]];
  for(i=0; i<[self length]; i++)
    {
      NSRange r;
      NSString *s;

      r = NSMakeRange(i, 1);
      s = [self substringWithRange: r];
      if([s isEqualToString: @"="] && i < [self length]-2)
      {
        unsigned char c;
        NSString *hex;
        
        r = NSMakeRange(i+1, 2);
        hex = [self substringWithRange: r];
        c = (unsigned char)[hex hexLongValue];

        [str appendString: [NSString stringWithFormat: @"%c", c]];
        i+=2;
      }
      else
      [str appendString: s];
    }

  str = [NSString stringWithUTF8String: [str cString]];
  return str;
}

- (NSString*) stringByQuotedPrintableEncoding
{
  int i;
  const unsigned char *cstr;
  NSMutableString *str;

  cstr = [self UTF8String];
  
  str = [NSMutableString stringWithCapacity: strlen(cstr)];
  for(i=0; i<strlen(cstr); i++)
    {
      if(cstr[i] == ' ')
      [str appendString: @"=20"];
      else if(cstr[i] > 127)
      [str appendFormat: @"=%X", cstr];
      else
      [str appendFormat: @"%c", cstr];
    }
  return str;
}
@end

@interface NSArray(VCFKeys)
- (NSString*) restOfStringStartingWith: (NSString*) start;
@end

@implementation NSArray(VCFKeys)
- (NSString*) restOfStringStartingWith: (NSString*) start
{
  NSEnumerator *e;
  id obj;

  e = [self objectEnumerator];
  while((obj = [e nextObject]))
    {
      if(![obj isKindOfClass: [NSString class]])
      continue;
      if([obj length] < [start length])
      continue;
      if([[obj substringToIndex: [start length]]
         isEqualToString: start])
      return [obj substringFromIndex: [start length]];
    }
  return nil;
}
@end

NSData *base64Decode(NSString* nsstr)
{
  char *b64chars;
  int i, j;
  unsigned char *bytes; const char *str;

  b64chars =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

  str = [nsstr lossyCString];
  
  bytes = (unsigned char*)calloc(([nsstr length]/4)*3, 1);
  
  for(i=0, j=0; i < strlen(str); i+=4, j+=3)
    {
      unsigned char s1, s2, s3, s4;
      u_int32_t v;

      while(!strchr(b64chars, str[i]) && i<strlen(str))
      i++;
      if(i>=strlen(str))
      {
        NSLog(@"Error: No good characters in string\n");
        break;
      }
      
      s1 = strchr(b64chars, str[i]) - b64chars;
      s2 = strchr(b64chars, str[i+1]) - b64chars;
      s3 = strchr(b64chars, str[i+2]) - b64chars;
      s4 = strchr(b64chars, str[i+3]) - b64chars;
      v = (s1 << 18) | (s2 << 12) | (s3 << 6) | s4;
      bytes = (v & 0xff0000) >> 16;
      bytes = (v & 0xff00) >> 8;
      bytes = v & 0xff;
    }
  return [NSData dataWithBytes: bytes length: ([nsstr length]/4)*3];
}

NSString *base64Encode(NSData* data)
{
  char *b64chars;
  unsigned char *bytes; int len;
  NSMutableString *str;
  int i, j;

  b64chars =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  bytes = (unsigned char*) [data bytes]; len = [data length];
  str = [NSMutableString stringWithCapacity: len*3];

  for(i=0,j=0; i<len-2; i+=3,j+=4)
    {
      unsigned char s1, s2, s3, s4;
      u_int32_t v;

      v = (bytes << 16);
      v |= (bytes << 8);
      v |= bytes;

      s1 = b64chars;
      s2 = b64chars;
      s3 = b64chars;
      s4 = b64chars;

      [str appendFormat: @"%c%c%c%c", s4, s3, s2, s1];
    }
      
  return [NSString stringWithString: str];
}  
  
      
@interface ADVCFConverter(Private)
- (BOOL) parseLine: (int) line
       fromArray: (NSArray*) arr
        upToLine: (int*) retLine
      intoKeyBlock: (NSArray**) k
      valueBlock: (NSArray**) v;
- (void) integrateKeyBlock: (NSArray*) k
            valueBlock: (NSArray*) v
            intoPerson: (ADPerson*) p;
- (void) appendStringForProperty: (NSString*) property
                  inPerson: (ADPerson*) p;
- (void) appendStringWithHeader: (NSString*) header
                    value: (NSString*) value;
- (void) appendStringWithHeader: (NSString*) header
                    value: (NSString*) value
            binaryLinebreak: (BOOL) blb;
@end

static NSArray *knownItems;

@implementation ADVCFConverter
+ (void) initialize
{
  knownItems =
    [[NSArray alloc] initWithObjects: @"org", @"role", @"url", @"adr",
                 @"n", @"agent", @"logo", @"photo", @"label", @"fn",
                 @"title", @"sound", @"version", @"tel", @"email",
                 @"tz", @"geo", @"note", @"bday", @"rev", @"uid",
                 @"key", @"mailer", nil];
}

- (void) dealloc
{
  [_str release];
  [_out release];
}

- initForInput
{
  _input = YES;
  _str = nil;
  _out = nil;
  return [super init];
}

- (BOOL) useString: (NSString*) str
{
  _str = [str copy];
  _idx = 0;

  return YES; 
}

- (ADRecord*) nextRecord
{
  int i = 0;
  NSString *str;
  NSArray *lines;
  ADPerson *person;

  person = [[[ADPerson alloc] init] autorelease];
  [person setValue: [NSDate date] forProperty: ADModificationDateProperty];
  [person setValue: [NSDate date] forProperty: ADCreationDateProperty];
  
  str = [_str substringFromIndex: _idx];

  lines = [str componentsSeparatedByString: @"\n"];
  
  while(i < [lines count])
    {
      NSArray *keyblock, *valueblock;
      BOOL retval;
      int oldIndex, newIndex;

      oldIndex = i;
      retval = [self parseLine: i
                 fromArray: lines
                 upToLine: &i
                 intoKeyBlock: &keyblock
                 valueBlock: &valueblock];
      newIndex = i;
      while(oldIndex < newIndex)
      _idx += [[lines objectAtIndex: oldIndex++] length] + 1;
      
      if(retval)
      {
        if([keyblock containsObject: @"end"]) // done!
          return person;
           
        if(![keyblock containsObject: @"begin"] &&
           ![keyblock containsObject: @"end"] &&
           ![keyblock containsObject: @"version"])
          [self integrateKeyBlock: keyblock
              valueBlock: valueblock
              intoPerson: person];
        }
      }
  
  return nil;
}

/* COutputConverting */
- initForOutput
{
  _str = nil;
  _input = NO;
  _idx = 0;
  _out = [[NSMutableString alloc] init];
  return self;
}

- (BOOL) canStoreMultipleRecords
{
  return YES;
}

- (void) storeRecord: (ADRecord*) record
{
  NSEnumerator *e; NSString *prop; NSString *name; id val;
  NSArray *myProps;

  if(![record isKindOfClass: [ADPerson class]])
    {
      NSLog(@"Can't store objects of class %@\n", [record className]);
      return;
    }
  
  myProps = [NSArray arrayWithObjects: ADLastNameProperty, ADFirstNameProperty,
           ADMiddleNameProperty, ADTitleProperty, nil];

  [_out appendString: @"BEGIN:VCARD\r\n"];
  [_out appendString: @"VERSION:2.1\r\n"];
  [_out appendString: @"X-GENERATOR:Addresses for GNUstep pre-1.0\r\n"];

  // Create name ourselves
  name = @"";
  e = [myProps objectEnumerator];
  while((prop = [e nextObject]))
    {
      val = [record valueForProperty: prop];
      name = [name stringByAppendingFormat: @"%@;", val ? val : @""];
    }
  val = [record valueForProperty: ADSuffixProperty];
  name = [name stringByAppendingFormat: @"%@", val ? val : @""];
  [self appendStringWithHeader: @"N" value: name];
  
  e = [[[record class] properties] objectEnumerator];
  while((prop = [e nextObject]))
    {
      if(![myProps containsObject: prop] &&
       ![prop isEqualToString: ADSuffixProperty])
      [self appendStringForProperty: prop inPerson: (ADPerson*) record];
    }

  [_out appendString: @"END:VCARD\r\n"];
}

- (NSString*) string
{
  return _out;
}
@end

@implementation ADVCFConverter (Private)
- (BOOL) parseLine: (int) line
       fromArray: (NSArray*) arr
        upToLine: (int*) retLine
      intoKeyBlock: (NSArray**) k
      valueBlock: (NSArray**) v
{
  NSString *str, *keyblock, *value;
  NSCharacterSet *wsp;
  NSRange r;

  wsp = [NSCharacterSet whitespaceAndNewlineCharacterSet];
  *retLine = line;
  
  str = [[arr objectAtIndex: (*retLine)++]
          stringByTrimmingCharactersInSet: wsp];

  if(![str length]) return NO;
  while(*retLine < [arr count] &&
      [[arr objectAtIndex: *retLine] length] &&
      [[[arr objectAtIndex: *retLine]
         substringWithRange: NSMakeRange(0, 1)]
        isEqualToString: @" "])
    {
      NSString *str2;

      str2 = [[arr objectAtIndex: (*retLine)++]
             stringByTrimmingCharactersInSet: wsp];
      str = [str stringByAppendingString: @" "];
      str = [str stringByAppendingString: str2];
    }
             
  r = [str rangeOfString: @":"];
  if(r.location == NSNotFound)
    {
      NSLog(@"Syntax error in line %d!\n", line);
      return NO;
    }
  
  keyblock = [str substringToIndex: r.location];
  *k = [[keyblock lowercaseString] componentsSeparatedByString: @";"];
  
  value = [str substringFromIndex: r.location+r.length];

  if([value isEqualToString: @"="]) // escape to next line
    {
      value = [[arr objectAtIndex: (*retLine)++]
            stringByTrimmingCharactersInSet: wsp];
      *v = [[value stringByQuotedPrintableDecoding]
           componentsSeparatedByString: @";"];
    }
  else
    *v = [[value stringByQuotedPrintableDecoding]
         componentsSeparatedByString: @";"];

  return YES;
}

- (void) integrateKeyBlock: (NSArray*) k
            valueBlock: (NSArray*) v
            intoPerson: (ADPerson*) p
{
  NSString* key;

  if(![k count])
    {
      NSLog(@"No keys in '%@':'%@'\n", k, v);
      return;
    }
  else if(![v count])
    {
      NSLog(@"No values in '%@':'%@'\n", k, v);
      return;
    }
  
  key = [k objectAtIndex: 0];
#if 0
  if(![knownItems containsObject: key])
    {
      NSLog(@"%@ not in knownItems\n", key);
      return;
    }
#endif

  if([key isEqualToString: @"n"])
    {
      if([v count] != 5)
      NSLog(@"Value for '%@':'%@' doesn't have enough entries!\n",
            k, v);

      [p setValue: [v objectAtIndex: 0] forProperty: ADLastNameProperty];
      if([v count] > 1)
      [p setValue: [v objectAtIndex: 1] forProperty: ADFirstNameProperty];
      if([v count] > 2)
      [p setValue: [v objectAtIndex: 2] forProperty: ADMiddleNameProperty];
      if([v count] > 3)
      [p setValue: [v objectAtIndex: 3] forProperty: ADTitleProperty];
      if([v count] > 4)
      [p setValue: [v objectAtIndex: 4] forProperty: ADSuffixProperty];
    }

  else if([key isEqualToString: @"org"])
    [p setValue: [v objectAtIndex: 0] forProperty: ADOrganizationProperty];
  else if([key isEqualToString: @"title"])
    [p setValue: [v objectAtIndex: 0] forProperty: ADJobTitleProperty];
  else if([key isEqualToString: @"url"])
    [p setValue: [v objectAtIndex: 0] forProperty: ADHomePageProperty];

  else if([key isEqualToString: @"bday"])
    {
      NSCalendarDate *d;

      d = [NSCalendarDate dateWithString: [v objectAtIndex: 0]
                    calendarFormat: @"%Y-%d-%m"];
      if(!d)
      d = [NSCalendarDate dateWithString: [v objectAtIndex: 0]
                      calendarFormat: @"%Y%d%m"];
      if(d) 
      [p setValue: d forProperty: ADBirthdayProperty];
      else
      NSLog(@"Can't convert %@ to date\n", [v objectAtIndex: 0]);
    }
  
  else if([key isEqualToString: @"note"])
    [p setValue: [v objectAtIndex: 0] forProperty: ADNoteProperty];

  // phone -- multi-string
  else if([key isEqualToString: @"tel"])
    {
      ADMutableMultiValue *mv;
      NSString *val;

      mv = [[[ADMutableMultiValue alloc]
            initWithMultiValue: [p valueForProperty: ADPhoneProperty]]
           autorelease];
      val = [v objectAtIndex: 0];
      if([k containsObject: @"fax"])
      {
        if([k containsObject: @"home"])
          [mv addValue: val withLabel: ADPhoneHomeFAXLabel];
        else
          [mv addValue: val withLabel: ADPhoneWorkFAXLabel];
      }
      else if([k containsObject: @"pager"])
      {
        [mv addValue: val withLabel: ADPhonePagerLabel];
      }
      else // assume "voice" for everything else
      {
        if([k containsObject: @"main"])
          [mv addValue: val withLabel: ADPhoneMainLabel];
        else if([k containsObject: @"cell"])
          [mv addValue: val withLabel: ADPhoneMobileLabel];
        else if([k containsObject: @"home"])
          [mv addValue: val withLabel: ADPhoneHomeLabel];
        else
          [mv addValue: val withLabel: ADPhoneWorkLabel];
      }
      [p setValue: mv forProperty: ADPhoneProperty];
    }

  // email -- multi-string
  else if([key isEqualToString: @"email"])
    {
      ADMutableMultiValue *mv;

      mv = [[[ADMutableMultiValue alloc]
            initWithMultiValue: [p valueForProperty: ADEmailProperty]]
           autorelease];

      if([k containsObject: @"home"])
      [mv addValue: [v objectAtIndex: 0] withLabel: ADEmailHomeLabel];
      else
      [mv addValue: [v objectAtIndex: 0] withLabel: ADEmailWorkLabel];

      [p setValue: mv forProperty: ADEmailProperty];
    }

  else if([key isEqualToString: @"adr"])
    {
      ADMutableMultiValue *mv;

      NSMutableDictionary *dict;
      NSString *poBox, *extendedAddr, *street, *locality, *region,
      *postalCode, *countryName;

      mv = [[[ADMutableMultiValue alloc]
            initWithMultiValue: [p valueForProperty: ADAddressProperty]]
           autorelease];

      dict = [NSMutableDictionary dictionaryWithCapacity: 6];
      poBox        = [v objectAtIndex: 0];
      extendedAddr = [v objectAtIndex: 1];
      street       = [v objectAtIndex: 2];
      locality     = [v objectAtIndex: 3];
      region       = [v objectAtIndex: 4];
      postalCode   = [v objectAtIndex: 5];
      countryName  = [v objectAtIndex: 6];


      if(street && ![street isEqualToString: @""])
      [dict setObject: street forKey: ADAddressStreetKey];
      if(locality && ![locality isEqualToString: @""])
      [dict setObject: locality forKey: ADAddressCityKey];
      if(region && ![region isEqualToString: @""])
      [dict setObject: region forKey: ADAddressStateKey];
      if(postalCode && ![postalCode isEqualToString: @""])
      [dict setObject: postalCode forKey: ADAddressZIPKey];
      if(countryName && ![countryName isEqualToString: @""])
      [dict setObject: countryName forKey: ADAddressCountryKey];
      if(poBox && ![poBox isEqualToString: @""])
      [dict setObject: poBox forKey: ADAddressPOBoxKey];
      if(extendedAddr && ![extendedAddr isEqualToString: @""])
      [dict setObject: extendedAddr forKey: ADAddressExtendedAddressKey];
      
      if([k containsObject: @"home"])
      [mv addValue: dict withLabel: ADAddressHomeLabel];
      else
      [mv addValue: dict withLabel: ADAddressWorkLabel];

      [p setValue: mv forProperty: ADAddressProperty];
    }

  else if([key isEqualToString: @"photo"])
    {
      NSString *encoding;
      NSString *type;
      NSData *data;

      encoding = [k restOfStringStartingWith: @"encoding="];
      if(![encoding isEqualToString: @"base64"])
      {
        NSLog(@"Cannot integrate image -- unknown "
            @"encoding '%@'\n", encoding);
        return;
      }
      type = [k restOfStringStartingWith: @"type="];

      data = base64Decode([v objectAtIndex: 0]);

      // Let's hope NSImage handles this
      [p setImageData: data];
      if(type)
      [p setImageDataType: type];
    }

  // FIXME: The following keys (specified in the vcard spec) aren't
  // handled by this converter yet, because they're not in the Apple
  // spec, but should perhaps be: 
  // @"label" -- free-form postal delivery label text
  // @"key"   -- public key
  // @"rev"   -- last revision in ISO8601 format, which NSDate can't
  //             parse (yet)
}

- (void) appendStringForProperty: (NSString*) prop
                  inPerson: (ADPerson*) p
{
  id val; int i; NSString *label, *identifier, *vcfLabel, *hdr, *fmt;

  val = [p valueForProperty: prop];
  if(!val || ([val respondsToSelector: @selector(count)] && ![val count]))
    return;

  if([prop isEqualToString: ADOrganizationProperty])
    [self appendStringWithHeader: @"ORG" value: val];
  else if([prop isEqualToString: ADJobTitleProperty])
    [self appendStringWithHeader: @"TITLE" value: val];
  else if([prop isEqualToString: ADHomePageProperty])
    [self appendStringWithHeader: @"URL" value: val];
  else if([prop isEqualToString: ADNoteProperty])
    [self appendStringWithHeader: @"NOTE" value: val];
  else if([prop isEqualToString: ADPhoneProperty]) // multi-string
    {
      NSString *value;

      for(i=0; i<[val count]; i++)
      {
        value = [val valueAtIndex: i];
        identifier = [val identifierAtIndex: i];
        label = [val labelAtIndex: i];
        vcfLabel = @"";

        if([label isEqualToString: ADPhoneWorkLabel] ||
           [label isEqualToString: ADWorkLabel])
          vcfLabel = @"WORK;VOICE;";
        else if([label isEqualToString: ADPhoneHomeLabel] ||
              [label isEqualToString: ADHomeLabel])
          vcfLabel = @"HOME;VOICE;";
        else if([label isEqualToString: ADPhoneMobileLabel])
          vcfLabel = @"CELL;VOICE;";
        else if([label isEqualToString: ADPhoneMainLabel])
          vcfLabel = @"PREF;VOICE;";
        else if([label isEqualToString: ADPhoneHomeFAXLabel])
          vcfLabel = @"HOME;FAX;";
        else if([label isEqualToString: ADPhoneWorkFAXLabel])
          vcfLabel = @"WORK;FAX;";
        else if([label isEqualToString: ADPhonePagerLabel])
          vcfLabel = @"PAGER;";
        else if([label isEqualToString: ADOtherLabel])
          vcfLabel = @"OTHER;";

        hdr = [NSString stringWithFormat: @"TEL;%@X-GNUSTEPLABEL=%@;"
                    @"X-GNUSTEPID=%@;%d", vcfLabel, label,
                    identifier, i+1];
        [self appendStringWithHeader: hdr
            value: value];
      }
    }
  else if([prop isEqualToString: ADEmailProperty])
    {
      NSString *value;

      for(i=0; i<[val count]; i++)
      {
        value = [val valueAtIndex: i];
        identifier = [val identifierAtIndex: i];
        label = [val labelAtIndex: i];
        vcfLabel = @"";

        if([label isEqualToString: ADEmailWorkLabel] ||
           [label isEqualToString: ADWorkLabel])
          vcfLabel = @"WORK;";
        else if([label isEqualToString: ADEmailHomeLabel] ||
              [label isEqualToString: ADHomeLabel])
          vcfLabel = @"HOME;";
        else if([label isEqualToString: ADOtherLabel])
          vcfLabel = @"OTHER;";

        hdr =
          [NSString stringWithFormat: @"EMAIL;INTERNET;%@X-GNUSTEPLABEL=%@;"
                  @"X-GNUSTEPID=%@;%d", vcfLabel, label, identifier, i+1];
        [self appendStringWithHeader: hdr
            value: value];
      }
    }
  else if([prop isEqualToString: ADAddressProperty])
    {
      NSDictionary *value;
      NSString *poBox, *extAddr, *street, *locality,
      *region, *postalCode, *country;

      for(i=0; i<[val count]; i++)
      {
        value = [val valueAtIndex: i];
        identifier = [val identifierAtIndex: i];
        label = [val labelAtIndex: i];
        vcfLabel = @"";

        if([label isEqualToString: ADAddressWorkLabel] ||
           [label isEqualToString: ADWorkLabel])
          vcfLabel = @"WORK;";
        else if([label isEqualToString: ADAddressHomeLabel] ||
              [label isEqualToString: ADHomeLabel])
          vcfLabel = @"HOME;";
        else if([label isEqualToString: ADOtherLabel])
          vcfLabel = @"OTHER;";

        poBox = [value objectForKey: ADAddressPOBoxKey];
        if(!poBox) poBox = @"";
        extAddr = [value objectForKey: ADAddressExtendedAddressKey];
        if(!extAddr) extAddr = @"";
        street = [value objectForKey: ADAddressStreetKey];
        if(!street) street = @"";
        locality = [value objectForKey: ADAddressCityKey];
        if(!locality) locality = @"";
        region = [value objectForKey: ADAddressStateKey];
        if(!region) region = @"";
        postalCode = [value objectForKey: ADAddressZIPKey];
        if(!postalCode) postalCode = @"";
        country = [value objectForKey: ADAddressCountryKey];
        if(!country) country = @"";

        hdr = [NSString stringWithFormat: @"ADR;%@X-GNUSTEPLABEL=%@;"
                    @"X-GNUSTEPID=%@;%d", vcfLabel, label,
                    identifier, i+1];
        fmt = [NSString stringWithFormat: @"%@;%@;%@;%@;%@;%@;%@",
                    poBox, extAddr, street, locality, region,
                    postalCode, country];
        [self appendStringWithHeader: hdr value: fmt];
      }      
    }
  else if([prop isEqualToString: ADImageProperty])
    {
      hdr = [NSString stringWithFormat: @"PHOTO;TYPE=%@;ENCODING=BASE64",
                  [[p valueForProperty: ADImageTypeProperty]
                  uppercaseString]];
      [self appendStringWithHeader: hdr
          value: base64Encode(val)
          binaryLinebreak: YES];
    }
  else if([prop isEqualToString: ADBirthdayProperty])
    [self appendStringWithHeader: @"BDAY"
        value: [val descriptionWithCalendarFormat: @"%Y-%d-%m"]];
  else
    NSLog(@"Warning: Unhandled property '%@' in conversion to vcard\n",
        prop);
}

- (void) appendStringWithHeader: (NSString*) header
                    value: (NSString*) value
{
  return [self appendStringWithHeader: header
             value: value
             binaryLinebreak: NO];
}

- (void) appendStringWithHeader: (NSString*) header
                    value: (NSString*) value
            binaryLinebreak: (BOOL) blb
{
  const char *str1, *str2;

  str1 = [value lossyCString];
  str2 = [value UTF8String];
  if(strcmp(str1, str2) != 0)
    {
      value = [value stringByQuotedPrintableEncoding];
      header = [header stringByAppendingString:
                   @";ENCODING=QUOTED-PRINTABLE;CHARSET=UTF-8"];
    }

  if(!([value length] >= 76) || !blb)
    [_out appendFormat: @"%@:%@\r\n", header, value];
  else
    {
      int i;

      [_out appendFormat: @"%@:\r\n", header];
      for(i=0; i<[value length]; i+=76)
      {
        NSString *substr;

        substr = [value substringFromIndex: i];
        if([substr length] > 76)
          substr = [value substringWithRange: NSMakeRange(i, 76)];

        [_out appendFormat: @" %@\r\n", substr];
      }
    }
}
@end

Generated by  Doxygen 1.6.0   Back to index