Pushr (master) :  summary log tree commit diff
path: root/tests/upload_to_flickr.m blob: 20ddef78349f5260ab3681590cc9511144414eed
1#import <CoreFoundation/CoreFoundation.h>
2#import <CoreServices/CoreServices.h>
3#import <Foundation/Foundation.h>
4
5#include <unistd.h>
6#include <openssl/md5.h>
7
8#define FLICKR_UPLOAD_URL @"http://api.flickr.com/services/upload/"
9#define FLICKR_FINISHED_URL @"http://www.flickr.com/tools/uploader_edit.gne"
10#define MIME_BOUNDARY "----16c17a9ea1d7b327e7489190e394d411----"
11#define CONTENT_TYPE "multipart/form-data; boundary=" MIME_BOUNDARY
12
13NSString *api_sig(NSDictionary *params)
14{
15 NSMutableString *sig = [NSMutableString stringWithString: PUSHR_SHARED_SECRET];
16 NSArray *sortedKeys = [[params allKeys] sortedArrayUsingSelector: @selector(caseInsensitiveCompare:)];
17
18 id key = nil;
19 NSEnumerator *iterator = [sortedKeys objectEnumerator];
20 while ((key = [iterator nextObject])) {
21 [sig appendString: key];
22 [sig appendString: [params objectForKey: key]];
23 }
24
25 unsigned char digest[16];
26 char finalDigest[32];
27
28 MD5((const unsigned char *)[sig UTF8String], (const unsigned long)[sig length], digest);
29 for (unsigned short int index = 0; index < 16; ++index)
30 sprintf(finalDigest + (index * 2), "%02x", digest[index]);
31
32 return [NSString stringWithCString: finalDigest length: 32];
33}
34
35void uploadPictureToFlickr(NSString *pathToJPG)
36{
37 NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];
38 NSString *token = [settings stringForKey: @"token"];
39 NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys: PUSHR_API_KEY, @"api_key", token, @"auth_token", @"0", @"is_public", nil];
40 [params setObject: api_sig(params) forKey: @"api_sig"];
41 [params setObject: [NSData dataWithContentsOfFile: pathToJPG] forKey: @"photo"];
42
43 NSMutableData *body = [[NSMutableData alloc] initWithLength: 0];
44 [body appendData: [[[[NSString alloc] initWithFormat: @"--%@\r\n", @MIME_BOUNDARY] autorelease] dataUsingEncoding: NSUTF8StringEncoding]];
45
46 id key = nil;
47 NSEnumerator *enumerator = [params keyEnumerator];
48 while ((key = [enumerator nextObject])) {
49 id val = [params objectForKey: key];
50 id keyHeader = nil;
51 if ([key isEqualToString: @"photo"]) {
52 // If this is the photo...
53 keyHeader = [[NSString stringWithFormat: @"Content-Disposition: form-data; name=\"photo\"; filename=\"%@\"\r\nContent-Type: image/jpeg\r\n\r\n", pathToJPG] dataUsingEncoding: NSUTF8StringEncoding];
54 [body appendData: keyHeader];
55 [body appendData: val];
56 } else {
57 // Treat all other values as strings.
58 keyHeader = [NSString stringWithFormat: @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key];
59 [body appendData: [keyHeader dataUsingEncoding: NSUTF8StringEncoding]];
60 [body appendData: [val dataUsingEncoding: NSUTF8StringEncoding]];
61 }
62 [body appendData: [[NSString stringWithFormat: @"\r\n--%@\r\n", @MIME_BOUNDARY] dataUsingEncoding: NSUTF8StringEncoding]];
63 }
64
65 [body appendData: [[NSString stringWithString: @"--\r\n"] dataUsingEncoding: NSUTF8StringEncoding]];
66 long bodyLength = [body length];
67
68 CFURLRef uploadURL = CFURLCreateWithString(kCFAllocatorDefault, (CFStringRef)FLICKR_UPLOAD_URL, NULL);
69 CFHTTPMessageRef _request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("POST"), uploadURL, kCFHTTPVersion1_1);
70 CFRelease(uploadURL);
71 uploadURL = NULL;
72
73 CFHTTPMessageSetHeaderFieldValue(_request, CFSTR("Content-Type"), CFSTR(CONTENT_TYPE));
74 CFHTTPMessageSetHeaderFieldValue(_request, CFSTR("Host"), CFSTR("api.flickr.com"));
75 CFHTTPMessageSetHeaderFieldValue(_request, CFSTR("Content-Length"), (CFStringRef)[NSString stringWithFormat: @"%d", bodyLength]);
76 CFHTTPMessageSetBody(_request, (CFDataRef)body);
77 [body release];
78
79 CFReadStreamRef _readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, _request);
80 CFReadStreamOpen(_readStream);
81
82 CFIndex numBytesRead;
83 long bytesWritten, previousBytesWritten = 0;
84 UInt8 buf[1024];
85 BOOL doneUploading = NO;
86
87 while (!doneUploading) {
88 CFNumberRef cfSize = CFReadStreamCopyProperty(_readStream, kCFStreamPropertyHTTPRequestBytesWrittenCount);
89 CFNumberGetValue(cfSize, kCFNumberLongType, &bytesWritten);
90 CFRelease(cfSize);
91 cfSize = NULL;
92 if (bytesWritten > previousBytesWritten) {
93 previousBytesWritten = bytesWritten;
94 fprintf(stderr, "(%lu bytes written / %lu total bytes) = %f %%\r", bytesWritten, bodyLength, (100.0f * ((float)bytesWritten/(float)bodyLength)));
95 fflush(stderr);
96 }
97
98 if (!CFReadStreamHasBytesAvailable(_readStream)) {
99 usleep(3200);
100 continue;
101 } else {
102 fprintf(stderr, "\n");
103 }
104
105 numBytesRead = CFReadStreamRead(_readStream, buf, 1024);
106 fprintf(stderr, "%s", buf);
107 fflush(stderr);
108
109 if (CFReadStreamGetStatus(_readStream) == kCFStreamStatusAtEnd) doneUploading = YES;
110 }
111 CFHTTPMessageRef _responseHeaderRef = (CFHTTPMessageRef)CFReadStreamCopyProperty(_readStream, kCFStreamPropertyHTTPResponseHeader);
112 NSDictionary *_responseHeaders = (NSDictionary *)CFHTTPMessageCopyAllHeaderFields(_responseHeaderRef);
113 NSLog(@"Header data was: \n---\n%@\n---\n", _responseHeaders);
114 CFRelease(_responseHeaderRef);
115 _responseHeaderRef = NULL;
116
117 CFReadStreamClose(_readStream);
118 CFRelease(_request);
119 _request = NULL;
120 CFRelease(_readStream);
121 _readStream = NULL;
122}
123
124int main(int argc, char *argv[])
125{
126 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
127
128 fprintf(stderr, "Pausing to give you time to catch me\n");
129 sleep(8);
130
131 for (unsigned int indexOfPicture = 1; indexOfPicture < argc; ++indexOfPicture) {
132 uploadPictureToFlickr([NSString stringWithUTF8String: argv[indexOfPicture]]);
133 fprintf(stderr, "Sleeping - check memory usage now!\n");
134 sleep(8);
135 }
136
137 [pool release];
138 return 0;
139}
140