Failed miserably at making Audioscrobbler submissions work.
[MenuTunes.git] / AudioscrobblerController.m
1 /*
2  *      MenuTunes
3  *  AudioscrobblerController
4  *    Audioscrobbler Support Class
5  *
6  *  Original Author : Kent Sutherland <kent.sutherland@ithinksw.com>
7  *   Responsibility : Kent Sutherland <kent.sutherland@ithinksw.com>
8  *
9  *  Copyright (c) 2005 iThink Software.
10  *  All Rights Reserved
11  *
12  */
13
14 #import "AudioscrobblerController.h"
15 #import <openssl/evp.h>
16
17 static AudioscrobblerController *_sharedController = nil;
18
19 @implementation AudioscrobblerController
20
21 + (void)load
22 {
23         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
24         [[AudioscrobblerController sharedController] submitTrack:@"Stairway To Heaven" artist:@"Led Zeppelin" album:@"Led Zeppelin IV" length:483];
25         [pool release];
26 }
27
28 + (AudioscrobblerController *)sharedController
29 {
30         if (!_sharedController) {
31                 _sharedController = [[AudioscrobblerController alloc] init];
32         }
33         return _sharedController;
34 }
35
36 - (id)init
37 {
38         if ( (self = [super init]) ) {
39                 _handshakeCompleted = NO;
40                 _responseData = nil;
41                 _md5Challenge = nil;
42                 _postURL = nil;
43                 
44                 //Test variables
45                 _md5Challenge = @"315EFDA9FDA6A24B421BE991511DEE90";
46                 _postURL = [[NSURL alloc] initWithString:@"http://62.216.251.205:80/protocol_1.1"];
47                 _handshakeCompleted = YES;
48                 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAudioscrobblerNotification:) name:nil object:self];
49         }
50         return self;
51 }
52
53 - (void)dealloc
54 {
55         [_md5Challenge release];
56         [_postURL release];
57         [_responseData release];
58         [super dealloc];
59 }
60
61 - (void)attemptHandshake
62 {
63         NSString *version = [[[NSBundle bundleWithPath:[[NSWorkspace sharedWorkspace] fullPathForApplication:@"iTunes.app"]] infoDictionary] objectForKey:@"CFBundleVersion"], *user = @"Tristrex";
64         NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://post.audioscrobbler.com/?hs=true&p=1.1&c=tst&v=%@&u=%@", version, user]];
65         NSURLConnection *connection;
66         
67         _currentStatus = AudioscrobblerRequestingHandshakeStatus;
68         _responseData = [[NSMutableData alloc] init];
69         connection = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30] delegate:self];
70 }
71
72 - (BOOL)handshakeCompleted
73 {
74         return _handshakeCompleted;
75 }
76
77 - (void)submitTrack:(NSString *)title artist:(NSString *)artist album:(NSString *)album length:(int)length
78 {
79         if (!_handshakeCompleted) {
80                 [self attemptHandshake];
81                 return;
82         }
83         
84         //What we eventually want is a submission list that sends backlogs also
85         NSMutableURLRequest *request = [[NSURLRequest requestWithURL:_postURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30] mutableCopy];
86         NSString *responseHash, *requestBody;
87         
88         char *pass = "waffles";
89         unsigned char *buffer, *buffer2, buffer3[16];
90         EVP_MD_CTX ctx;
91         int i;
92         
93         buffer = malloc(EVP_MD_size(EVP_md5()));
94         //buffer3 = malloc(EVP_MD_size(EVP_md5()));
95         
96         EVP_DigestInit(&ctx, EVP_md5());
97         EVP_DigestUpdate(&ctx, pass, strlen(pass));
98         EVP_DigestUpdate(&ctx, [_md5Challenge UTF8String], strlen([_md5Challenge UTF8String]));
99         EVP_DigestFinal(&ctx, buffer, NULL);
100         
101         for (i = 0; i < 16; i++) {
102                 char hex1, hex2;
103                 hex1 = toascii(48+ (buffer[i] / 16));
104                 if (hex1 > 57) {
105                         hex1 = hex1 + 39;
106                 }
107                 hex2 = toascii(48 + (buffer[i] % 16));
108                 if (hex2 > 57) {
109                         hex2 = hex2 + 39;
110                 }
111                 
112                 buffer3[i] = hex1;
113                 buffer3[i + 1] = hex2;
114         }
115         
116         NSLog(@"%s", buffer3);
117         
118         /*unsigned char *cat = strcat(buffer3, [[_md5Challenge lowercaseString] UTF8String]);
119         
120         EVP_DigestInit(&ctx, EVP_md5());
121         EVP_DigestUpdate(&ctx, cat, strlen(cat));
122         EVP_DigestFinal(&ctx, buffer2, NULL);
123         
124         for (i = 0; i < 16; i++) {
125                 char hex1, hex2;
126                 hex1 = toascii(48+ (buffer2[i] / 16));
127                 if (hex1 > 57) {
128                         hex1 = hex1 + 39;
129                 }
130                 hex2 = toascii(48 + (buffer2[i] % 16));
131                 if (hex2 > 57) {
132                         hex2 = hex2 + 39;
133                 }
134                 buffer3[i] = hex1;
135                 buffer3[i + 1] = hex2;
136         }
137         NSLog(@"%s", buffer3);*/
138         
139         if ([NSString respondsToSelector:@selector(stringWithCString:encoding:)]) {
140                 responseHash = [NSString stringWithCString:buffer3 encoding:NSASCIIStringEncoding];
141         } else {
142                 responseHash = [NSString stringWithCString:buffer3 length:strlen(buffer)];
143         }
144         
145         requestBody = [NSString stringWithFormat:@"u=%@&s=%@&a[0]=%@&t[0]=%@&b[0]=%@&m[0]=&l[0]=%i&i[0]=%@", @"Tristrex", @"rawr", responseHash, title, album, length, [[NSDate date] descriptionWithCalendarFormat:@"%Y-%m-%d %H:%M:%S" timeZone:nil locale:nil]];
146         [request setHTTPMethod:@"POST"];
147         [request setHTTPBody:[requestBody dataUsingEncoding:NSUTF8StringEncoding]];
148         
149         _currentStatus = AudioscrobblerSubmittingTrackStatus;
150         _responseData = [[NSMutableData alloc] init];
151         [NSURLConnection connectionWithRequest:request delegate:self];
152         [request release];
153 }
154
155 - (void)handleAudioscrobblerNotification:(NSNotification *)note
156 {
157         if ([[note name] isEqualToString:@"AudioscrobblerHandshakeComplete"]) {
158                 [[AudioscrobblerController sharedController] submitTrack:@"Stairway To Heaven" artist:@"Led Zeppelin" album:@"Led Zeppelin IV" length:483];
159         }
160 }
161
162 #pragma mark -
163
164 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
165 {
166         NSLog(@"Failed with an error: %@", error);
167 }
168
169 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
170 {
171         [_responseData appendData:data];
172 }
173
174 - (void)connectionDidFinishLoading:(NSURLConnection *)connection
175 {
176         NSString *string = [[NSString alloc] initWithData:_responseData encoding:NSASCIIStringEncoding];
177         
178         if (_currentStatus == AudioscrobblerRequestingHandshakeStatus) {
179                 NSArray *lines = [string componentsSeparatedByString:@"\n"];
180                 NSString *responseAction;
181                 if ([lines count] < 2) {
182                         //We have an error
183                 }
184                 responseAction = [lines objectAtIndex:0];
185                 if ([responseAction isEqualToString:@"UPTODATE"]) {
186                         if ([lines count] >= 4) {
187                                 _md5Challenge = [[lines objectAtIndex:1] retain];
188                                 _postURL = [[NSURL alloc] initWithString:[lines objectAtIndex:2]];
189                                 _handshakeCompleted = YES;
190                                 NSLog(@"%@", _md5Challenge);
191                                 [[NSNotificationCenter defaultCenter] postNotificationName:@"AudioscrobblerHandshakeComplete" object:self];
192                         } else {
193                                 //We have an error
194                         }
195                         //Something
196                 } else if (([responseAction length] > 6) && [[responseAction substringToIndex:5] isEqualToString:@"UPDATE"]) {
197                         //Something plus update action
198                 } else if (([responseAction length] > 6) && [[responseAction substringToIndex:5] isEqualToString:@"FAILED"]) {
199                         //We have an error
200                 } else if ([responseAction isEqualToString:@"BADUSER"]) {
201                         //We have an error
202                 } else {
203                         //We have an error
204                 }
205         } else if (_currentStatus == AudioscrobblerSubmittingTrackStatus) {
206                 NSLog(string);
207         }
208         
209         [string release];
210 }
211
212 @end