<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>OACall.h</filename>
    </added>
    <added>
      <filename>OACall.m</filename>
    </added>
    <added>
      <filename>OAProblem.h</filename>
    </added>
    <added>
      <filename>OAProblem.m</filename>
    </added>
    <added>
      <filename>OATokenManager.h</filename>
    </added>
    <added>
      <filename>OATokenManager.m</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -29,7 +29,9 @@
 
 @interface NSMutableURLRequest (OAParameterAdditions)
 
-- (NSArray *)parameters;
-- (void)setParameters:(NSArray *)parameters;
+@property(nonatomic, retain) NSArray *parameters;
+
+- (void)setHTTPBodyWithString:(NSString *)body;
+- (void)attachFileWithName:(NSString *)name filename:(NSString*)filename contentType:(NSString *)contentType data:(NSData*)data;
 
 @end</diff>
      <filename>Categories/NSMutableURLRequest+Parameters.h</filename>
    </modified>
    <modified>
      <diff>@@ -25,25 +25,31 @@
 
 #import &quot;NSMutableURLRequest+Parameters.h&quot;
 
+static NSString *Boundary = @&quot;-----------------------------------0xCoCoaouTHeBouNDaRy&quot;; 
 
 @implementation NSMutableURLRequest (OAParameterAdditions)
 
+- (BOOL)isMultipart {
+	return [[self valueForHTTPHeaderField:@&quot;Content-Type&quot;] hasPrefix:@&quot;multipart/form-data&quot;];
+}
+
 - (NSArray *)parameters {
-    NSString *encodedParameters;
+    NSString *encodedParameters = nil;
     
-    if ([[self HTTPMethod] isEqualToString:@&quot;GET&quot;] || [[self HTTPMethod] isEqualToString:@&quot;DELETE&quot;]) {
-        encodedParameters = [[self URL] query];
-    } else {
-        // POST, PUT
-        encodedParameters = [[NSString alloc] initWithData:[self HTTPBody] encoding:NSASCIIStringEncoding];
-    }
+	if (![self isMultipart]) {
+		if ([[self HTTPMethod] isEqualToString:@&quot;GET&quot;] || [[self HTTPMethod] isEqualToString:@&quot;DELETE&quot;]) {
+			encodedParameters = [[self URL] query];
+		} else {
+			encodedParameters = [[[NSString alloc] initWithData:[self HTTPBody] encoding:NSASCIIStringEncoding] autorelease];
+		}
+	}
     
-    if ((encodedParameters == nil) || ([encodedParameters isEqualToString:@&quot;&quot;])) {
+    if (encodedParameters == nil || [encodedParameters isEqualToString:@&quot;&quot;]) {
         return nil;
     }
-    
+    NSLog(@&quot;raw parameters %@&quot;, encodedParameters);
     NSArray *encodedParameterPairs = [encodedParameters componentsSeparatedByString:@&quot;&amp;&quot;];
-    NSMutableArray *requestParameters = [[NSMutableArray alloc] initWithCapacity:16];
+    NSMutableArray *requestParameters = [NSMutableArray arrayWithCapacity:[encodedParameterPairs count]];
     
     for (NSString *encodedPair in encodedParameterPairs) {
         NSArray *encodedPairElements = [encodedPair componentsSeparatedByString:@&quot;=&quot;];
@@ -55,27 +61,52 @@
     return requestParameters;
 }
 
-- (void)setParameters:(NSArray *)parameters {
-    NSMutableString *encodedParameterPairs = [[NSMutableString alloc] initWithCapacity:256];
+- (void)setParameters:(NSArray *)parameters
+{
+	NSMutableArray *pairs = [[[NSMutableArray alloc] initWithCapacity:[parameters count]] autorelease];
+	for (OARequestParameter *requestParameter in parameters) {
+		[pairs addObject:[requestParameter URLEncodedNameValuePair]];
+	}
+	
+	NSString *encodedParameterPairs = [pairs componentsJoinedByString:@&quot;&amp;&quot;];
     
-    int position = 1;
-    for (OARequestParameter *requestParameter in parameters) {
-        [encodedParameterPairs appendString:[requestParameter URLEncodedNameValuePair]];
-        if (position &lt; [parameters count]) {
-            [encodedParameterPairs appendString:@&quot;&amp;&quot;];
-        }
-        position++;
-    }
-    
-    if ([[self HTTPMethod] isEqualToString:@&quot;GET&quot;] || [[self HTTPMethod] isEqualToString:@&quot;DELETE&quot;]) {
-        [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@&quot;%@?%@&quot;, [[self URL] URLStringWithoutQuery], encodedParameterPairs]]];
-    } else {
-        // POST, PUT
-        NSData *postData = [encodedParameterPairs dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
-        [self setHTTPBody:postData];
-        [self setValue:[NSString stringWithFormat:@&quot;%d&quot;, [postData length]] forHTTPHeaderField:@&quot;Content-Length&quot;];
-        [self setValue:@&quot;application/x-www-form-urlencoded&quot; forHTTPHeaderField:@&quot;Content-Type&quot;];
-    }
+	if ([[self HTTPMethod] isEqualToString:@&quot;GET&quot;] || [[self HTTPMethod] isEqualToString:@&quot;DELETE&quot;]) {
+		[self setURL:[NSURL URLWithString:[NSString stringWithFormat:@&quot;%@?%@&quot;, [[self URL] URLStringWithoutQuery], encodedParameterPairs]]];
+	} else {
+		// POST, PUT
+		[self setHTTPBodyWithString:encodedParameterPairs];
+		[self setValue:@&quot;application/x-www-form-urlencoded&quot; forHTTPHeaderField:@&quot;Content-Type&quot;];
+	}
+}
+
+- (void)setHTTPBodyWithString:(NSString *)body {
+	NSData *bodyData = [body dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
+	[self setValue:[NSString stringWithFormat:@&quot;%d&quot;, [bodyData length]] forHTTPHeaderField:@&quot;Content-Length&quot;];
+	[self setHTTPBody:bodyData];
+}
+
+- (void)attachFileWithName:(NSString *)name filename:(NSString*)filename contentType:(NSString *)contentType data:(NSData*)data {
+
+	NSArray *parameters = [self parameters];
+	[self setValue:[@&quot;multipart/form-data; boundary=&quot; stringByAppendingString:Boundary] forHTTPHeaderField:@&quot;Content-type&quot;];
+	
+	NSMutableData *bodyData = [NSMutableData new];
+	for (OARequestParameter *parameter in parameters) {
+		NSString *param = [NSString stringWithFormat:@&quot;--%@\r\nContent-Disposition: form-data; name=\&quot;%@\&quot;\r\n\r\n%@\r\n&quot;,
+						   Boundary, [parameter URLEncodedName], [parameter value]];
+
+		[bodyData appendData:[param dataUsingEncoding:NSUTF8StringEncoding]];
+	}
+
+	NSString *filePrefix = [NSString stringWithFormat:@&quot;--%@\r\nContent-Disposition: form-data; name=\&quot;%@\&quot;; filename=\&quot;%@\&quot;\r\nContent-Type: %@\r\n\r\n&quot;,
+		Boundary, name, filename, contentType];
+	[bodyData appendData:[filePrefix dataUsingEncoding:NSUTF8StringEncoding]];
+	[bodyData appendData:data];
+	
+	[bodyData appendData:[[[@&quot;--&quot; stringByAppendingString:Boundary] stringByAppendingString:@&quot;--&quot;] dataUsingEncoding:NSUTF8StringEncoding]];
+	[self setValue:[NSString stringWithFormat:@&quot;%d&quot;, [bodyData length]] forHTTPHeaderField:@&quot;Content-Length&quot;];
+	[self setHTTPBody:bodyData];
+	[bodyData release];
 }
 
 @end</diff>
      <filename>Categories/NSMutableURLRequest+Parameters.m</filename>
    </modified>
    <modified>
      <diff>@@ -30,5 +30,6 @@
 
 - (NSString *)encodedURLString;
 - (NSString *)encodedURLParameterString;
-
+- (NSString *)decodedURLString;
+- (NSString *)removeQuotes;
 @end</diff>
      <filename>Categories/NSString+URLEncoding.h</filename>
    </modified>
    <modified>
      <diff>@@ -34,7 +34,7 @@
                                                                            NULL,                   // characters to leave unescaped (NULL = all escaped sequences are replaced)
                                                                            CFSTR(&quot;?=&amp;+&quot;),          // legal URL characters to be escaped (NULL = all legal characters are replaced)
                                                                            kCFStringEncodingUTF8); // encoding
-	return result;
+	return [result autorelease];
 }
 
 - (NSString *)encodedURLParameterString {
@@ -43,7 +43,31 @@
                                                                            NULL,
                                                                            CFSTR(&quot;:/=,!$&amp;'()*+;[]@#?&quot;),
                                                                            kCFStringEncodingUTF8);
-	return result;
+	return [result autorelease];
+}
+
+- (NSString *)decodedURLString {
+	NSString *result = (NSString*)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,
+																						  (CFStringRef)self,
+																						  CFSTR(&quot;&quot;),
+																						  kCFStringEncodingUTF8);
+	
+	return [result autorelease];
+	
+}
+
+-(NSString *)removeQuotes
+{
+	NSUInteger length = [self length];
+	NSString *ret = self;
+	if ([self characterAtIndex:0] == '&quot;') {
+		ret = [ret substringFromIndex:1];
+	}
+	if ([self characterAtIndex:length - 1] == '&quot;') {
+		ret = [ret substringToIndex:length - 2];
+	}
+	
+	return ret;
 }
 
 @end</diff>
      <filename>Categories/NSString+URLEncoding.m</filename>
    </modified>
    <modified>
      <diff>@@ -35,6 +35,8 @@
 @property(copy, readwrite) NSString *key;
 @property(copy, readwrite) NSString *secret;
 
-- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret;
+- (id)initWithKey:(const NSString *)aKey secret:(const NSString *)aSecret;
+
+- (BOOL)isEqualToConsumer:(OAConsumer *)aConsumer;
 
 @end</diff>
      <filename>OAConsumer.h</filename>
    </modified>
    <modified>
      <diff>@@ -31,11 +31,23 @@
 
 #pragma mark init
 
-- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret {
+- (id)initWithKey:(const NSString *)aKey secret:(const NSString *)aSecret {
 	[super init];
-	self.key = aKey;
-	self.secret = aSecret;
+	self.key = [aKey retain];
+	self.secret = [aSecret retain];
 	return self;
 }
 
+- (BOOL)isEqual:(id)object {
+	if ([object isKindOfClass:[self class]]) {
+		return [self isEqualToConsumer:(OAConsumer*)object];
+	}
+	return NO;
+}
+
+- (BOOL)isEqualToConsumer:(OAConsumer *)aConsumer {
+	return ([self.key isEqualToString:aConsumer.key] &amp;&amp;
+			[self.secret isEqualToString:aConsumer.secret]);
+}
+
 @end</diff>
      <filename>OAConsumer.m</filename>
    </modified>
    <modified>
      <diff>@@ -33,8 +33,7 @@
     OAMutableURLRequest *request;
     NSURLResponse *response;
     NSURLConnection *connection;
-    NSError *error;
-    NSData *responseData;
+    NSMutableData *responseData;
     id delegate;
     SEL didFinishSelector;
     SEL didFailSelector;</diff>
      <filename>OADataFetcher.h</filename>
    </modified>
    <modified>
      <diff>@@ -29,33 +29,58 @@
 
 @implementation OADataFetcher
 
+- (id)init {
+	[super init];
+	responseData = [[NSMutableData alloc] init];
+	return self;
+}
+
+- (void)dealloc {
+	[connection release];
+	[response release];
+	[responseData release];
+	[request release];
+	[super dealloc];
+}
+
+/* Protocol for async URL loading */
+- (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSURLResponse *)aResponse {
+	[response release];
+	response = [aResponse retain];
+	[responseData setLength:0];
+}
+	
+- (void)connection:(NSURLConnection *)aConnection didFailWithError:(NSError *)error {
+	OAServiceTicket *ticket = [[OAServiceTicket alloc] initWithRequest:request
+															  response:response
+																  data:responseData
+															didSucceed:NO];
+
+	[delegate performSelector:didFailSelector withObject:ticket withObject:error];
+}
+
+- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
+	[responseData appendData:data];
+}
+
+- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
+	OAServiceTicket *ticket = [[OAServiceTicket alloc] initWithRequest:request
+															  response:response
+																  data:responseData
+															didSucceed:[(NSHTTPURLResponse *)response statusCode] &lt; 400];
+
+	[delegate performSelector:didFinishSelector withObject:ticket withObject:responseData];
+}
+
 - (void)fetchDataWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector {
-    request = aRequest;
+	request = [aRequest retain];
     delegate = aDelegate;
     didFinishSelector = finishSelector;
     didFailSelector = failSelector;
     
     [request prepare];
-    
-    responseData = [NSURLConnection sendSynchronousRequest:request
-                                         returningResponse:&amp;response
-                                                     error:&amp;error];
-											
-    if (response == nil || responseData == nil || error != nil) {
-        OAServiceTicket *ticket= [[OAServiceTicket alloc] initWithRequest:request
-                                                                 response:response
-                                                               didSucceed:NO];
-        [delegate performSelector:didFailSelector
-                       withObject:ticket
-                       withObject:error];
-    } else {
-        OAServiceTicket *ticket = [[OAServiceTicket alloc] initWithRequest:request
-                                                                  response:response
-                                                                didSucceed:[(NSHTTPURLResponse *)response statusCode] &lt; 400];
-        [delegate performSelector:didFinishSelector
-                       withObject:ticket
-                       withObject:responseData];
-    }   
+
+	connection = [[NSURLConnection alloc] initWithRequest:aRequest delegate:self];
 }
 
 @end</diff>
      <filename>OADataFetcher.m</filename>
    </modified>
    <modified>
      <diff>@@ -98,28 +98,30 @@ signatureProvider:(id&lt;OASignatureProviding, NSObject&gt;)aProvider
 
 - (void)prepare {
     // sign
-    signature = [signatureProvider signClearText:[self _signatureBaseString]
+	NSLog(@&quot;Base string is: %@&quot;, [self _signatureBaseString]);
+   signature = [signatureProvider signClearText:[self _signatureBaseString]
                                       withSecret:[NSString stringWithFormat:@&quot;%@&amp;%@&quot;,
                                                   consumer.secret,
-                                                  token.secret]];
+                                                  token.secret ? token.secret : @&quot;&quot;]];
     
     // set OAuth headers
-    
-    NSString *oauthToken;
-    if ([token.key isEqualToString:@&quot;&quot;]) {
-        oauthToken = @&quot;&quot;; // not used on Request Token transactions
-    } else {
-        oauthToken = [NSString stringWithFormat:@&quot;oauth_token=\&quot;%@\&quot;, &quot;, [token.key encodedURLParameterString]];
-    }
-    
-    NSString *oauthHeader = [NSString stringWithFormat:@&quot;OAuth realm=\&quot;%@\&quot;, oauth_consumer_key=\&quot;%@\&quot;, %@oauth_signature_method=\&quot;%@\&quot;, oauth_signature=\&quot;%@\&quot;, oauth_timestamp=\&quot;%@\&quot;, oauth_nonce=\&quot;%@\&quot;, oauth_version=\&quot;1.0\&quot;&quot;,
-                             [realm encodedURLParameterString],
-                             [consumer.key encodedURLParameterString],
-                             oauthToken,
-                             [[signatureProvider name] encodedURLParameterString],
-                             [signature encodedURLParameterString],
-                             timestamp,
-                             nonce];
+	NSMutableArray *chunks = [[NSMutableArray alloc] init];
+	[chunks addObject:[NSString stringWithFormat:@&quot;realm=\&quot;%@\&quot;&quot;, [realm encodedURLParameterString]]];
+	[chunks addObject:[NSString stringWithFormat:@&quot;oauth_consumer_key=\&quot;%@\&quot;&quot;, [consumer.key encodedURLParameterString]]];
+
+	NSDictionary *tokenParameters = [token parameters];
+	for (NSString *k in tokenParameters) {
+		[chunks addObject:[NSString stringWithFormat:@&quot;%@=\&quot;%@\&quot;&quot;, k, [[tokenParameters objectForKey:k] encodedURLParameterString]]];
+	}
+
+	[chunks addObject:[NSString stringWithFormat:@&quot;oauth_signature_method=\&quot;%@\&quot;&quot;, [[signatureProvider name] encodedURLParameterString]]];
+	[chunks addObject:[NSString stringWithFormat:@&quot;oauth_signature=\&quot;%@\&quot;&quot;, [signature encodedURLParameterString]]];
+	[chunks addObject:[NSString stringWithFormat:@&quot;oauth_timestamp=\&quot;%@\&quot;&quot;, timestamp]];
+	[chunks addObject:[NSString stringWithFormat:@&quot;oauth_nonce=\&quot;%@\&quot;&quot;, nonce]];
+	[chunks	addObject:@&quot;oauth_version=\&quot;1.0\&quot;&quot;];
+	
+	NSString *oauthHeader = [NSString stringWithFormat:@&quot;OAuth %@&quot;, [chunks componentsJoinedByString:@&quot;, &quot;]];
+	[chunks release];
 
     [self setValue:oauthHeader forHTTPHeaderField:@&quot;Authorization&quot;];
 }
@@ -138,25 +140,31 @@ signatureProvider:(id&lt;OASignatureProviding, NSObject&gt;)aProvider
 - (NSString *)_signatureBaseString {
     // OAuth Spec, Section 9.1.1 &quot;Normalize Request Parameters&quot;
     // build a sorted array of both request parameters and OAuth header parameters
-    NSMutableArray *parameterPairs = [[NSMutableArray alloc] initWithCapacity:(6 + [[self parameters] count])]; // 6 being the number of OAuth params in the Signature Base String
+	NSDictionary *tokenParameters = [token parameters];
+	// 6 being the number of OAuth params in the Signature Base String
+	NSMutableArray *parameterPairs = [[NSMutableArray alloc] initWithCapacity:(5 + [[self parameters] count] + [tokenParameters count])];
     
     [parameterPairs addObject:[[[OARequestParameter alloc] initWithName:@&quot;oauth_consumer_key&quot; value:consumer.key] URLEncodedNameValuePair]];
     [parameterPairs addObject:[[[OARequestParameter alloc] initWithName:@&quot;oauth_signature_method&quot; value:[signatureProvider name]] URLEncodedNameValuePair]];
     [parameterPairs addObject:[[[OARequestParameter alloc] initWithName:@&quot;oauth_timestamp&quot; value:timestamp] URLEncodedNameValuePair]];
     [parameterPairs addObject:[[[OARequestParameter alloc] initWithName:@&quot;oauth_nonce&quot; value:nonce] URLEncodedNameValuePair]];
     [parameterPairs addObject:[[[OARequestParameter alloc] initWithName:@&quot;oauth_version&quot; value:@&quot;1.0&quot;] URLEncodedNameValuePair]];
+	
+
+	for(NSString *k in tokenParameters) {
+		[parameterPairs addObject:[[OARequestParameter requestParameter:k value:[tokenParameters objectForKey:k]] URLEncodedNameValuePair]];
+	}
     
-    if (![token.key isEqualToString:@&quot;&quot;]) {
-        [parameterPairs addObject:[[[OARequestParameter alloc] initWithName:@&quot;oauth_token&quot; value:token.key] URLEncodedNameValuePair]];
-    }
-    
-    for (OARequestParameter *param in [self parameters]) {
-        [parameterPairs addObject:[param URLEncodedNameValuePair]];
-    }
+	if (![[self valueForHTTPHeaderField:@&quot;Content-Type&quot;] hasPrefix:@&quot;multipart/form-data&quot;]) {
+		for (OARequestParameter *param in [self parameters]) {
+			[parameterPairs addObject:[param URLEncodedNameValuePair]];
+		}
+	}
     
     NSArray *sortedPairs = [parameterPairs sortedArrayUsingSelector:@selector(compare:)];
     NSString *normalizedRequestParameters = [sortedPairs componentsJoinedByString:@&quot;&amp;&quot;];
     
+	NSLog(@&quot;Normalized: %@&quot;, normalizedRequestParameters);
     // OAuth Spec, Section 9.1.2 &quot;Concatenate Request Elements&quot;
     return [NSString stringWithFormat:@&quot;%@&amp;%@&amp;%@&quot;,
             [self HTTPMethod],</diff>
      <filename>OAMutableURLRequest.m</filename>
    </modified>
    <modified>
      <diff>@@ -41,4 +41,8 @@
 - (NSString *)URLEncodedValue;
 - (NSString *)URLEncodedNameValuePair;
 
+- (BOOL)isEqualToRequestParameter:(OARequestParameter *)parameter;
+
++ (id)requestParameter:(NSString *)aName value:(NSString *)aValue;
+
 @end</diff>
      <filename>OARequestParameter.h</filename>
    </modified>
    <modified>
      <diff>@@ -38,7 +38,8 @@
 }
 
 - (NSString *)URLEncodedName {
-    return [self.name encodedURLParameterString];
+	return self.name;
+//    return [self.name encodedURLParameterString];
 }
 
 - (NSString *)URLEncodedValue {
@@ -49,4 +50,23 @@
     return [NSString stringWithFormat:@&quot;%@=%@&quot;, [self URLEncodedName], [self URLEncodedValue]];
 }
 
+- (BOOL)isEqual:(id)object {
+	if ([object isKindOfClass:[self class]]) {
+		return [self isEqualToRequestParameter:(OARequestParameter *)object];
+	}
+	
+	return NO;
+}
+
+- (BOOL)isEqualToRequestParameter:(OARequestParameter *)parameter {
+	return ([self.name isEqualToString:parameter.name] &amp;&amp;
+			[self.value isEqualToString:parameter.value]);
+}
+
+
++ (id)requestParameter:(NSString *)aName value:(NSString *)aValue
+{
+	return [[[self alloc] initWithName:aName value:aValue] autorelease];
+}
+
 @end</diff>
      <filename>OARequestParameter.m</filename>
    </modified>
    <modified>
      <diff>@@ -32,12 +32,15 @@
 @private
     OAMutableURLRequest *request;
     NSURLResponse *response;
+	NSData *data;
     BOOL didSucceed;
 }
 @property(readonly) OAMutableURLRequest *request;
 @property(readonly) NSURLResponse *response;
+@property(readonly) NSData *data;
 @property(readonly) BOOL didSucceed;
+@property(readonly) NSString *body;
 
-- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSURLResponse *)aResponse didSucceed:(BOOL)success;
+- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSURLResponse *)aResponse data:(NSData *)aData didSucceed:(BOOL)success;
 
 @end</diff>
      <filename>OAServiceTicket.h</filename>
    </modified>
    <modified>
      <diff>@@ -28,14 +28,24 @@
 
 
 @implementation OAServiceTicket
-@synthesize request, response, didSucceed;
+@synthesize request, response, data, didSucceed;
 
-- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSURLResponse *)aResponse didSucceed:(BOOL)success {
+- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSURLResponse *)aResponse data:(NSData *)aData didSucceed:(BOOL)success {
     [super init];
     request = aRequest;
     response = aResponse;
+	data = aData;
     didSucceed = success;
     return self;
 }
 
+- (NSString *)body
+{
+	if (!data) {
+		return nil;
+	}
+	
+	return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
+}
+
 @end</diff>
      <filename>OAServiceTicket.m</filename>
    </modified>
    <modified>
      <diff>@@ -29,13 +29,44 @@
 @protected
 	NSString *key;
 	NSString *secret;
+	NSString *session;
+	NSNumber *duration;
+	NSMutableDictionary *attributes;
+	NSDate *created;
+	BOOL renewable;
+	BOOL forRenewal;
 }
 @property(copy, readwrite) NSString *key;
 @property(copy, readwrite) NSString *secret;
+@property(copy, readwrite) NSString *session;
+@property(retain, readwrite) NSNumber *duration;
+@property(retain, readwrite) NSDictionary *attributes;
+@property(readwrite, getter=isForRenewal) BOOL forRenewal;
 
 - (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret;
-- (id)initWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix;
+- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret session:(NSString *)aSession
+		 duration:(NSNumber *)aDuration attributes:(NSDictionary *)theAttributes created:(NSDate *)creation
+		renewable:(BOOL)renew;
 - (id)initWithHTTPResponseBody:(NSString *)body;
+
+- (id)initWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix;
 - (int)storeInUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix;
 
+- (BOOL)isValid;
+
+- (void)setAttribute:(NSString *)aKey value:(NSString *)aValue;
+- (NSString *)attribute:(NSString *)aKey;
+- (void)setAttributesWithString:(NSString *)aAttributes;
+- (NSString *)attributeString;
+
+- (BOOL)hasExpired;
+- (BOOL)isRenewable;
+- (void)setDurationWithString:(NSString *)aDuration;
+- (BOOL)hasAttributes;
+- (NSDictionary *)parameters;
+
+- (BOOL)isEqualToToken:(OAToken *)aToken;
+
++ (void)removeFromUserDefaultsWithServiceProviderName:(const NSString *)provider prefix:(const NSString *)prefix;
+
 @end</diff>
      <filename>OAToken.h</filename>
    </modified>
    <modified>
      <diff>@@ -24,65 +24,301 @@
 //  THE SOFTWARE.
 
 
+#import &quot;NSString+URLEncoding.h&quot;
 #import &quot;OAToken.h&quot;
 
+@interface OAToken (Private)
+
++ (NSString *)settingsKey:(const NSString *)name provider:(const NSString *)provider prefix:(const NSString *)prefix;
++ (id)loadSetting:(const NSString *)name provider:(const NSString *)provider prefix:(const NSString *)prefix;
++ (void)saveSetting:(NSString *)name object:(id)object provider:(const NSString *)provider prefix:(const NSString *)prefix;
++ (NSNumber *)durationWithString:(NSString *)aDuration;
++ (NSDictionary *)attributesWithString:(NSString *)theAttributes;
+
+@end
 
 @implementation OAToken
 
-@synthesize key, secret;
+@synthesize key, secret, session, duration, attributes, forRenewal;
 
 #pragma mark init
 
 - (id)init {
-    [super init];
-    self.key = @&quot;&quot;;
-    self.secret = @&quot;&quot;;
-    return self;
+	return [self initWithKey:nil secret:nil];
 }
 
 - (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret {
+	return [self initWithKey:aKey secret:aSecret session:nil duration:nil
+				  attributes:nil created:nil renewable:NO];
+}
+
+- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret session:(NSString *)aSession
+		 duration:(NSNumber *)aDuration attributes:(NSDictionary *)theAttributes created:(NSDate *)creation
+		renewable:(BOOL)renew {
 	[super init];
 	self.key = aKey;
 	self.secret = aSecret;
+	self.session = aSession;
+	self.duration = aDuration;
+	self.attributes = theAttributes;
+	created = [creation retain];
+	renewable = renew;
+	forRenewal = NO;
+
 	return self;
 }
 
-- (id)initWithHTTPResponseBody:(NSString *)body {
-    [super init];
-    NSArray *pairs = [body componentsSeparatedByString:@&quot;&amp;&quot;];
-    
-    for (NSString *pair in pairs) {
+- (id)initWithHTTPResponseBody:(const NSString *)body {
+    NSString *aKey = nil;
+	NSString *aSecret = nil;
+	NSString *aSession = nil;
+	NSNumber *aDuration = nil;
+	NSDate *creationDate = nil;
+	NSDictionary *attrs = nil;
+	BOOL renew = NO;
+	NSArray *pairs = [body componentsSeparatedByString:@&quot;&amp;&quot;];
+
+	for (NSString *pair in pairs) {
         NSArray *elements = [pair componentsSeparatedByString:@&quot;=&quot;];
         if ([[elements objectAtIndex:0] isEqualToString:@&quot;oauth_token&quot;]) {
-            self.key = [elements objectAtIndex:1];
+            aKey = [elements objectAtIndex:1];
         } else if ([[elements objectAtIndex:0] isEqualToString:@&quot;oauth_token_secret&quot;]) {
-            self.secret = [elements objectAtIndex:1];
-        }
+            aSecret = [elements objectAtIndex:1];
+        } else if ([[elements objectAtIndex:0] isEqualToString:@&quot;oauth_session_handle&quot;]) {
+			aSession = [elements objectAtIndex:1];
+		} else if ([[elements objectAtIndex:0] isEqualToString:@&quot;oauth_token_duration&quot;]) {
+			aDuration = [[self class] durationWithString:[elements objectAtIndex:1]];
+			creationDate = [NSDate date];
+		} else if ([[elements objectAtIndex:0] isEqualToString:@&quot;oauth_token_attributes&quot;]) {
+			attrs = [[self class] attributesWithString:[[elements objectAtIndex:1] decodedURLString]];
+		} else if ([[elements objectAtIndex:0] isEqualToString:@&quot;oauth_token_renewable&quot;]) {
+			NSString *lowerCase = [[elements objectAtIndex:1] lowercaseString];
+			if ([lowerCase isEqualToString:@&quot;true&quot;] || [lowerCase isEqualToString:@&quot;t&quot;]) {
+				renew = YES;
+			}
+		}
     }
     
-    return self;
+    return [self initWithKey:aKey secret:aSecret session:aSession duration:aDuration
+				  attributes:attrs created:creationDate renewable:renew];
+}
+
+- (id)initWithUserDefaultsUsingServiceProviderName:(const NSString *)provider prefix:(const NSString *)prefix {
+	[super init];
+	key = [OAToken loadSetting:@&quot;key&quot; provider:provider prefix:prefix];
+	secret = [OAToken loadSetting:@&quot;secret&quot; provider:provider prefix:prefix];
+	session = [OAToken loadSetting:@&quot;session&quot; provider:provider prefix:prefix];
+	duration = [OAToken loadSetting:@&quot;duration&quot; provider:provider prefix:prefix];
+	attributes = [OAToken loadSetting:@&quot;attributes&quot; provider:provider prefix:prefix];
+	created = [OAToken loadSetting:@&quot;created&quot; provider:provider prefix:prefix];
+	renewable = [[OAToken loadSetting:@&quot;renewable&quot; provider:provider prefix:prefix] boolValue];
+	
+	if (![self isValid]) {
+		[self autorelease];
+		return nil;
+	}
+	
+	return self;
+}
+
+#pragma mark dealloc
+
+- (void)dealloc {
+	[key release];
+	[secret release];
+	[duration release];
+	[attributes release];
+	[super dealloc];
+}
+
+#pragma mark settings
+
+- (BOOL)isValid {
+	return (key != nil &amp;&amp; ![key isEqualToString:@&quot;&quot;] &amp;&amp; secret != nil &amp;&amp; ![secret isEqualToString:@&quot;&quot;]);
+}
+
+- (int)storeInUserDefaultsWithServiceProviderName:(const NSString *)provider prefix:(const NSString *)prefix {
+	[OAToken saveSetting:@&quot;key&quot; object:key provider:provider prefix:prefix];
+	[OAToken saveSetting:@&quot;secret&quot; object:secret provider:provider prefix:prefix];
+	[OAToken saveSetting:@&quot;created&quot; object:created provider:provider prefix:prefix];
+	[OAToken saveSetting:@&quot;duration&quot; object:duration provider:provider prefix:prefix];
+	[OAToken saveSetting:@&quot;session&quot; object:session provider:provider prefix:prefix];
+	[OAToken saveSetting:@&quot;attributes&quot; object:attributes provider:provider prefix:prefix];
+	[OAToken saveSetting:@&quot;renewable&quot; object:renewable ? @&quot;t&quot; : @&quot;f&quot; provider:provider prefix:prefix];
+	
+	[[NSUserDefaults standardUserDefaults] synchronize];
+	return(0);
+}
+
+#pragma mark duration
+
+- (void)setDurationWithString:(NSString *)aDuration {
+	self.duration = [[self class] durationWithString:aDuration];
+}
+
+- (BOOL)hasExpired
+{
+	return created &amp;&amp; [created timeIntervalSinceNow] &gt; [duration intValue];
+}
+
+- (BOOL)isRenewable
+{
+	return session &amp;&amp; renewable &amp;&amp; created &amp;&amp; [created timeIntervalSinceNow] &lt; (2 * [duration intValue]);
+}
+
+
+#pragma mark attributes
+
+- (void)setAttribute:(const NSString *)aKey value:(const NSString *)aAttribute {
+	if (!attributes) {
+		attributes = [[NSMutableDictionary alloc] init];
+	}
+	[attributes setObject: aAttribute forKey: aKey];
+}
+
+- (void)setAttributes:(NSDictionary *)theAttributes {
+	[attributes release];
+	attributes = [[NSMutableDictionary alloc] initWithDictionary:theAttributes];
+	
 }
 
+- (BOOL)hasAttributes {
+	return (attributes &amp;&amp; [attributes count] &gt; 0);
+}
+
+- (NSString *)attributeString {
+	if (![self hasAttributes]) {
+		return @&quot;&quot;;
+	}
+	
+	NSMutableArray *chunks = [[NSMutableArray alloc] init];
+	for(NSString *aKey in self-&gt;attributes) {
+		[chunks addObject:[NSString stringWithFormat:@&quot;%@:%@&quot;, aKey, [attributes objectForKey:aKey]]];
+	}
+	NSString *attrs = [chunks componentsJoinedByString:@&quot;;&quot;];
+	[chunks release];
+	return attrs;
+}
 
-- (id)initWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix
+- (NSString *)attribute:(NSString *)aKey
 {
-[super init];
-NSString *theKey = [[NSUserDefaults standardUserDefaults] stringForKey:[NSString stringWithFormat:@&quot;OAUTH_%@_%@_KEY&quot;, prefix, provider]];
-NSString *theSecret = [[NSUserDefaults standardUserDefaults] stringForKey:[NSString stringWithFormat:@&quot;OAUTH_%@_%@_SECRET&quot;, prefix, provider]];
-if (theKey == NULL || theSecret == NULL)
-	return(nil);
-self.key = theKey;
-self.secret = theSecret;
-return(self);
+	return [attributes objectForKey:aKey];
 }
 
+- (void)setAttributesWithString:(NSString *)theAttributes
+{
+	self.attributes = [[self class] attributesWithString:theAttributes];
+}
 
-- (int)storeInUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix
+- (NSDictionary *)parameters
 {
-[[NSUserDefaults standardUserDefaults] setObject:self.key forKey:[NSString stringWithFormat:@&quot;OAUTH_%@_%@_KEY&quot;, prefix, provider]];
-[[NSUserDefaults standardUserDefaults] setObject:self.secret forKey:[NSString stringWithFormat:@&quot;OAUTH_%@_%@_SECRET&quot;, prefix, provider]];
-[[NSUserDefaults standardUserDefaults] synchronize];
-return(0);
+	NSMutableDictionary *params = [[[NSMutableDictionary alloc] init] autorelease];
+
+	if (key) {
+		[params setObject:key forKey:@&quot;oauth_token&quot;];
+		if ([self isForRenewal]) {
+			[params setObject:session forKey:@&quot;oauth_session_handle&quot;];
+		}
+	} else {
+		if (duration) {
+			[params setObject:[duration stringValue] forKey: @&quot;oauth_token_duration&quot;];
+		}
+		if ([attributes count]) {
+			[params setObject:[self attributeString] forKey:@&quot;oauth_token_attributes&quot;];
+		}
+	}
+	return params;
+}
+
+#pragma mark comparisions
+
+- (BOOL)isEqual:(id)object {
+	if([object isKindOfClass:[self class]]) {
+		return [self isEqualToToken:(OAToken *)object];
+	}
+	return NO;
+}
+
+- (BOOL)isEqualToToken:(OAToken *)aToken {
+	/* Since ScalableOAuth determines that the token may be
+	 renewed using the same key and secret, we must also
+	 check the creation date */
+	if ([self.key isEqualToString:aToken.key] &amp;&amp;
+		[self.secret isEqualToString:aToken.secret]) {
+		/* May be nil */
+		if (created == aToken-&gt;created || [created isEqualToDate:aToken-&gt;created]) {
+			return YES;
+		}
+	}
+	
+	return NO;
+}
+			
+#pragma mark class_functions
+			
++ (NSString *)settingsKey:(NSString *)name provider:(NSString *)provider prefix:(NSString *)prefix {
+	return [NSString stringWithFormat:@&quot;OAUTH_%@_%@_%@&quot;, provider, prefix, [name uppercaseString]];
+}
+			
++ (id)loadSetting:(NSString *)name provider:(NSString *)provider prefix:(NSString *)prefix {
+	return [[NSUserDefaults standardUserDefaults] objectForKey:[self settingsKey:name
+																		provider:provider
+																		  prefix:prefix]];
+}
+			
++ (void)saveSetting:(NSString *)name object:(id)object provider:(NSString *)provider prefix:(NSString *)prefix {
+	[[NSUserDefaults standardUserDefaults] setObject:object forKey:[self settingsKey:name
+																			provider:provider
+																			  prefix:prefix]];
+}
+	
++ (void)removeFromUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix {
+	NSArray *keys = [NSArray arrayWithObjects:@&quot;key&quot;, @&quot;secret&quot;, @&quot;created&quot;, @&quot;duration&quot;, @&quot;session&quot;, @&quot;attributes&quot;, @&quot;renewable&quot;, nil];
+	for(NSString *name in keys) {
+		[[NSUserDefaults standardUserDefaults] removeObjectForKey:[OAToken settingsKey:name provider:provider prefix:prefix]];
+	}
+}
+			
++ (NSNumber *)durationWithString:(NSString *)aDuration {
+	NSUInteger length = [aDuration length];
+	unichar c = toupper([aDuration characterAtIndex:length - 1]);
+	int mult;
+	if (c &gt;= '0' &amp;&amp; c &lt;= '9') {
+		return [NSNumber numberWithInt:[aDuration intValue]];
+	}
+	if (c == 'S') {
+		mult = 1;
+	} else if (c == 'H') {
+		mult = 60 * 60;
+	} else if (c == 'D') {
+		mult = 60 * 60 * 24;
+	} else if (c == 'W') {
+		mult = 60 * 60 * 24 * 7;
+	} else if (c == 'M') {
+		mult = 60 * 60 * 24 * 30;
+	} else if (c == 'Y') {
+		mult = 60 * 60 * 365;
+	} else {
+		mult = 1;
+	}
+	
+	return [NSNumber numberWithInt: mult * [[aDuration substringToIndex:length - 1] intValue]];
+}
+
++ (NSDictionary *)attributesWithString:(NSString *)theAttributes {
+	NSArray *attrs = [theAttributes componentsSeparatedByString:@&quot;;&quot;];
+	NSMutableDictionary *dct = [[NSMutableDictionary alloc] init];
+	for (NSString *pair in attrs) {
+		NSArray *elements = [pair componentsSeparatedByString:@&quot;:&quot;];
+		[dct setObject:[elements objectAtIndex:1] forKey:[elements objectAtIndex:0]];
+	}
+	return [dct autorelease];
+}
+
+#pragma mark description
+
+- (NSString *)description {
+	return [NSString stringWithFormat:@&quot;Key \&quot;%@\&quot; Secret:\&quot;%@\&quot;&quot;, key, secret];
 }
 
 @end</diff>
      <filename>OAToken.m</filename>
    </modified>
    <modified>
      <diff>@@ -24,6 +24,7 @@
 //  THE SOFTWARE.
 
 #import &lt;Foundation/Foundation.h&gt;
+#import &quot;OAProblem.h&quot;
 #import &quot;OAuthConsumer/OAToken.h&quot;
 #import &quot;OAuthConsumer/OAConsumer.h&quot;
 #import &quot;OAuthConsumer/OAMutableURLRequest.h&quot;
@@ -35,4 +36,5 @@
 #import &quot;OAuthConsumer/OAPlaintextSignatureProvider.h&quot;
 #import &quot;OAuthConsumer/OARequestParameter.h&quot;
 #import &quot;OAuthConsumer/OAServiceTicket.h&quot;
-#import &quot;OAuthConsumer/OADataFetcher.h&quot;
\ No newline at end of file
+#import &quot;OAuthConsumer/OADataFetcher.h&quot;
+#import &quot;OATokenManager.h&quot;
\ No newline at end of file</diff>
      <filename>OAuthConsumer.h</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>12743182bc26faef071f4e274d7c0a7d9f49e63f</id>
    </parent>
  </parents>
  <author>
    <name>Jonathan George</name>
    <email>jonathan@jdg.net</email>
  </author>
  <url>http://github.com/jdg/oauthconsumer/commit/01ce025e01c89a84364d21b0b32de6907c80d666</url>
  <id>01ce025e01c89a84364d21b0b32de6907c80d666</id>
  <committed-date>2008-10-30T15:05:40-07:00</committed-date>
  <authored-date>2008-10-30T15:05:40-07:00</authored-date>
  <message>Add in extensions by Alberto Hierro (http://fi.am/)</message>
  <tree>f37fa19a28000049a1fc9ad4bd8c3d98cedbbc33</tree>
  <committer>
    <name>Jonathan George</name>
    <email>jonathan@jdg.net</email>
  </committer>
</commit>
