Changeset 3099
- Timestamp:
- 12/29/05 02:34:02 (3 years ago)
- Files:
-
- branches/cocoa-networking/Chat Core/MVFileTransfer.h (modified) (1 diff)
- branches/cocoa-networking/Chat Core/MVFileTransfer.m (modified) (9 diffs)
- branches/cocoa-networking/Chat Core/MVFileTransferPrivate.h (modified) (1 diff)
- branches/cocoa-networking/Chat Core/MVIRCChatConnection.h (modified) (3 diffs)
- branches/cocoa-networking/Chat Core/MVIRCChatConnection.m (modified) (5 diffs)
- branches/cocoa-networking/Chat Core/MVIRCFileTransfer.h (modified) (1 diff)
- branches/cocoa-networking/Chat Core/MVIRCFileTransfer.m (modified) (4 diffs)
- branches/cocoa-networking/Chat Core/MVSILCFileTransfer.m (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/cocoa-networking/Chat Core/MVFileTransfer.h
r3072 r3099 59 59 - (unsigned short) port; 60 60 61 - (void) setFinalSize:(unsigned long long) finalSize;62 - (void) setTransfered:(unsigned long long) transfered;63 - (void) setStartDate:(NSDate *) startDate;64 65 61 - (MVChatUser *) user; 66 62 branches/cocoa-networking/Chat Core/MVFileTransfer.m
r3075 r3099 58 58 if( ( self = [super init] ) ) { 59 59 _status = MVFileTransferHoldingStatus; 60 _port = 0;61 _startOffset = 0;62 _finalSize = 0;63 _transfered = 0;64 _startDate = nil;65 _host = nil;66 60 _user = [user retain]; 67 61 } … … 95 89 96 90 - (BOOL) isPassive { 97 // subclass if needed 98 return NO; 91 return _passive; 99 92 } 100 93 … … 135 128 - (unsigned short) port { 136 129 return _port; 137 }138 139 #pragma mark -140 141 - (void) setFinalSize:(unsigned long long) finalSize {142 @synchronized( self ) {143 _finalSize = finalSize;144 }145 }146 147 - (void) setTransfered:(unsigned long long) transfered {148 @synchronized( self ) {149 _transfered = transfered;150 }151 }152 153 - (void) setStartDate:(NSDate *) startDate {154 @synchronized( self ) {155 id old = _startDate;156 _startDate = [startDate retain];157 [old release];158 }159 130 } 160 131 … … 177 148 @implementation MVFileTransfer (MVFileTransferPrivate) 178 149 - (void) _setStatus:(MVFileTransferStatus) status { 179 @synchronized( self ) { 180 _status = status; 181 } 150 _status = status; 151 } 152 153 - (void) _setFinalSize:(unsigned long long) finalSize { 154 _finalSize = finalSize; 155 } 156 157 - (void) _setTransfered:(unsigned long long) transfered { 158 _transfered = transfered; 159 } 160 161 - (void) _setStartOffset:(unsigned long long) startOffset { 162 _startOffset = startOffset; 163 } 164 165 - (void) _setStartDate:(NSDate *) startDate { 166 id old = _startDate; 167 _startDate = [startDate retain]; 168 [old release]; 169 } 170 171 - (void) _setHost:(NSHost *) host { 172 id old = _host; 173 _host = [host retain]; 174 [old release]; 175 } 176 177 - (void) _setPort:(unsigned short) port { 178 _port = port; 179 } 180 181 - (void) _setPassive:(BOOL) passive { 182 _passive = passive; 182 183 } 183 184 … … 185 186 [self _setStatus:MVFileTransferErrorStatus]; 186 187 187 @synchronized( self ) { 188 id old = _lastError; 189 _lastError = [error retain]; 190 [old release]; 191 } 188 id old = _lastError; 189 _lastError = [error retain]; 190 [old release]; 192 191 193 192 NSDictionary *info = [[NSDictionary allocWithZone:nil] initWithObjectsAndKeys:error, @"error", nil]; 194 [[NSNotificationCenter defaultCenter] postNotification Name:MVFileTransferErrorOccurredNotification object:self userInfo:info];193 [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVFileTransferErrorOccurredNotification object:self userInfo:info]; 195 194 [info release]; 196 195 } … … 212 211 #pragma mark - 213 212 214 - (id) initWithUser:(MVChatUser *) user {215 if( ( self = [super initWithUser:user] ) )216 _source = nil;217 218 return self;219 }220 221 213 - (void) dealloc { 222 214 [_source release]; … … 240 232 #pragma mark - 241 233 234 @implementation MVUploadFileTransfer (MVUploadFileTransferPrivate) 235 - (void) _setSource:(NSString *) source { 236 id old = _source; 237 _source = [[source stringByStandardizingPath] retain]; 238 [old release]; 239 } 240 @end 241 242 #pragma mark - 243 242 244 @implementation MVDownloadFileTransfer 243 - (id) initWithUser:(MVChatUser *) user {244 if( ( self = [super initWithUser:user] ) ) {245 _destination = nil;246 _originalFileName = nil;247 }248 249 return self;250 }251 252 245 - (void) dealloc { 253 246 [_destination release]; … … 264 257 - (void) setDestination:(NSString *) path renameIfFileExists:(BOOL) rename { 265 258 // subclass if needed, call super 266 @synchronized( self ) { 267 id old = _destination; 268 _destination = [[path stringByStandardizingPath] copyWithZone:nil]; 269 [old release]; 270 } 259 id old = _destination; 260 _destination = [[path stringByStandardizingPath] copyWithZone:nil]; 261 [old release]; 271 262 } 272 263 … … 305 296 } 306 297 @end 298 299 #pragma mark - 300 301 @implementation MVDownloadFileTransfer (MVDownloadFileTransferPrivate) 302 - (void) _setOriginalFileName:(NSString *) originalFileName { 303 id old = _originalFileName; 304 _originalFileName = [originalFileName copyWithZone:nil]; 305 [old release]; 306 } 307 @end branches/cocoa-networking/Chat Core/MVFileTransferPrivate.h
r3081 r3099 3 3 @interface MVFileTransfer (MVFileTransferPrivate) 4 4 - (void) _setStatus:(MVFileTransferStatus) status; 5 - (void) _setFinalSize:(unsigned long long) finalSize; 6 - (void) _setTransfered:(unsigned long long) transfered; 7 - (void) _setStartOffset:(unsigned long long) startOffset; 8 - (void) _setStartDate:(NSDate *) startDate; 9 - (void) _setHost:(NSHost *) host; 10 - (void) _setPort:(unsigned short) port; 11 - (void) _setPassive:(BOOL) passive; 5 12 - (void) _postError:(NSError *) error; 6 13 @end 14 15 @interface MVUploadFileTransfer (MVUploadFileTransferPrivate) 16 - (void) _setSource:(NSString *) source; 17 @end 18 19 @interface MVDownloadFileTransfer (MVDownloadFileTransferPrivate) 20 - (void) _setOriginalFileName:(NSString *) originalFileName; 21 @end branches/cocoa-networking/Chat Core/MVIRCChatConnection.h
r3093 r3099 3 3 4 4 @class AsyncSocket; 5 @class MVFileTransfer; 5 6 6 7 @interface MVIRCChatConnection : MVChatConnection { … … 9 10 NSThread *_connectionThread; 10 11 NSMutableDictionary *_knownUsers; 12 NSMutableSet *_fileTransfers; 11 13 NSString *_server; 12 14 NSString *_currentNickname; … … 38 40 39 41 - (void) _updateKnownUser:(MVChatUser *) user withNewNickname:(NSString *) nickname; 42 43 - (void) _addFileTransfer:(MVFileTransfer *) transfer; 44 - (void) _removeFileTransfer:(MVFileTransfer *) transfer; 40 45 @end branches/cocoa-networking/Chat Core/MVIRCChatConnection.m
r3098 r3099 507 507 508 508 _knownUsers = [[NSMutableDictionary allocWithZone:nil] initWithCapacity:200]; 509 _fileTransfers = [[NSMutableSet allocWithZone:nil] initWithCapacity:5]; 509 510 } 510 511 … … 517 518 [_chatConnection release]; 518 519 [_knownUsers release]; 520 [_fileTransfers release]; 521 [_server release]; 522 [_currentNickname release]; 523 [_nickname release]; 524 [_username release]; 525 [_password release]; 526 [_realName release]; 527 [_proxyServer release]; 519 528 [_proxyUsername release]; 520 529 [_proxyPassword release]; … … 523 532 _connectionThread = nil; 524 533 _knownUsers = nil; 534 _fileTransfers = nil; 535 _server = nil; 536 _currentNickname = nil; 537 _nickname = nil; 538 _username = nil; 539 _password = nil; 540 _realName = nil; 541 _proxyServer = nil; 525 542 _proxyUsername = nil; 526 543 _proxyPassword = nil; … … 1279 1296 [self sendRawMessageWithComponents:prefix, msg, nil]; 1280 1297 [prefix release]; 1298 } 1299 } 1300 1301 - (void) _addFileTransfer:(MVFileTransfer *) transfer { 1302 @synchronized( _fileTransfers ) { 1303 if( transfer ) [_fileTransfers addObject:transfer]; 1304 } 1305 } 1306 1307 - (void) _removeFileTransfer:(MVFileTransfer *) transfer { 1308 @synchronized( _fileTransfers ) { 1309 if( transfer ) [_fileTransfers removeObject:transfer]; 1281 1310 } 1282 1311 } … … 1427 1456 // only reply with packets less than 100 bytes, anything over that is bad karma 1428 1457 if( [arguments length] < 100 ) [sender sendSubcodeReply:command withArguments:arguments]; 1458 } else if( [command caseInsensitiveCompare:@"DCC"] == NSOrderedSame ) { 1459 NSString *msg = [[NSString allocWithZone:nil] initWithData:arguments encoding:[self encoding]]; 1460 NSArray *parameters = [msg componentsSeparatedByString:@" "]; 1461 [msg release]; 1462 1463 if( [parameters count] >= 5 && [[parameters objectAtIndex:0] caseInsensitiveCompare:@"SEND"] == NSOrderedSame ) { 1464 long long size = 0; 1465 unsigned int port = [[parameters objectAtIndex:3] intValue]; 1466 NSScanner *scanner = [NSScanner scannerWithString:[parameters objectAtIndex:4]]; 1467 [scanner scanLongLong:&size]; 1468 1469 NSString *address = [parameters objectAtIndex:2]; 1470 if( [address rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@".:"]].location == NSNotFound ) { 1471 unsigned int ip4 = [address intValue]; 1472 address = [NSString stringWithFormat:@"%lu.%lu.%lu.%lu", (ip4 & 0xff000000) >> 24, (ip4 & 0x00ff0000) >> 16, (ip4 & 0x0000ff00) >> 8, (ip4 & 0x000000ff)]; 1473 } 1474 1475 NSHost *host = [NSHost hostWithAddress:address]; 1476 1477 MVIRCDownloadFileTransfer *transfer = [[MVIRCDownloadFileTransfer allocWithZone:nil] initWithUser:sender]; 1478 [transfer _setOriginalFileName:[parameters objectAtIndex:1]]; 1479 [transfer _setFinalSize:(unsigned long long)size]; 1480 [transfer _setHost:host]; 1481 [transfer _setPort:port]; 1482 [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVDownloadFileTransferOfferNotification object:transfer]; 1483 [self _addFileTransfer:transfer]; 1484 [transfer release]; 1485 } else if( [parameters count] >= 4 && [[parameters objectAtIndex:0] caseInsensitiveCompare:@"ACCEPT"] == NSOrderedSame ) { 1486 long long size = 0; 1487 unsigned int port = [[parameters objectAtIndex:2] intValue]; 1488 NSScanner *scanner = [NSScanner scannerWithString:[parameters objectAtIndex:3]]; 1489 [scanner scanLongLong:&size]; 1490 1491 @synchronized( _fileTransfers ) { 1492 NSEnumerator *enumerator = [_fileTransfers objectEnumerator]; 1493 MVFileTransfer *transfer = nil; 1494 while( ( transfer = [enumerator nextObject] ) ) { 1495 if( [transfer isDownload] && [[transfer user] isEqualToChatUser:sender] && [transfer port] == port ) { 1496 [transfer _setTransfered:(unsigned long long)size]; 1497 [transfer _setStartOffset:(unsigned long long)size]; 1498 [(MVIRCDownloadFileTransfer *)transfer _setupAndStart]; 1499 } 1500 } 1501 } 1502 } 1429 1503 } else if( [command caseInsensitiveCompare:@"CLIENTINFO"] == NSOrderedSame ) { 1430 1504 // make this extnesible later with a plugin registration method branches/cocoa-networking/Chat Core/MVIRCFileTransfer.h
r3081 r3099 2 2 #import "MVFileTransferPrivate.h" 3 3 4 @interface MVIRCUploadFileTransfer : MVUploadFileTransfer {} 4 @class AsyncSocket; 5 @class NSThread; 6 7 @interface MVIRCUploadFileTransfer : MVUploadFileTransfer { 8 AsyncSocket *_connection; 9 NSThread *_connectionThread; 10 } 5 11 @end 6 12 7 13 #pragma mark - 8 14 9 @interface MVIRCDownloadFileTransfer : MVDownloadFileTransfer {} 15 @interface MVIRCDownloadFileTransfer : MVDownloadFileTransfer { 16 AsyncSocket *_connection; 17 NSThread *_connectionThread; 18 NSFileHandle *_fileHandle; 19 BOOL _fileNameQuoted; 20 unsigned int _passiveId; 21 } 22 - (void) _setupAndStart; 10 23 @end branches/cocoa-networking/Chat Core/MVIRCFileTransfer.m
r3075 r3099 1 #import <sched.h> 1 2 2 3 #import "MVIRCFileTransfer.h" … … 4 5 #import "MVChatUser.h" 5 6 #import "NSNotificationAdditions.h" 6 7 /*static void MVFileTransferConnected( FILE_DCC_REC *dcc ) { 8 MVFileTransfer *self = [MVFileTransfer _transferForDCCFileRecord:dcc]; 9 if( ! self ) return; 10 11 [self _setStatus:MVFileTransferNormalStatus]; 12 13 NSNotification *note = [NSNotification notificationWithName:MVFileTransferStartedNotification object:self]; 14 [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:note]; 15 } 16 17 static void MVFileTransferUpdate( FILE_DCC_REC *dcc ) { 18 MVFileTransfer *self = [MVFileTransfer _transferForDCCFileRecord:dcc]; 19 if( ! self ) return; 20 21 if( [self status] == MVFileTransferStoppedStatus ) 22 dcc_close( (DCC_REC *) dcc ); 23 } 24 25 static void MVFileTransferClosed( FILE_DCC_REC *dcc ) { 7 #import "AsyncSocket.h" 8 #import "InterThreadMessaging.h" 9 10 #define DCCPacketSize 4096 11 12 /*static void MVFileTransferClosed( FILE_DCC_REC *dcc ) { 26 13 MVFileTransfer *self = [MVFileTransfer _transferForDCCFileRecord:dcc]; 27 14 if( ! self ) return; … … 42 29 } 43 30 44 static void MVFileTransferDestroyed( FILE_DCC_REC *dcc ) {45 MVFileTransfer *self = [MVFileTransfer _transferForDCCFileRecord:dcc];46 if( ! self ) return;47 48 [self performSelector:@selector( _destroying )];49 }50 51 31 static void MVFileTransferErrorConnect( FILE_DCC_REC *dcc ) { 52 32 MVFileTransfer *self = [MVFileTransfer _transferForDCCFileRecord:dcc]; … … 101 81 [error release]; 102 82 [info release]; 103 } 104 105 #pragma mark - 106 107 static BOOL fileTransferSignalsRegistered = NO; 108 109 @implementation MVFileTransfer (MVIRCFileTransferPrivate) 110 + (id) _transferForDCCFileRecord:(FILE_DCC_REC *) record { 111 if( ! record ) return nil; 112 113 MVFileTransferModuleData *data = MODULE_DATA( record ); 114 if( data ) return [[(data -> transfer) retain] autorelease]; 115 116 return nil; 117 } 118 @end 119 120 #pragma mark - */ 83 } */ 84 85 #pragma mark - 121 86 122 87 @implementation MVIRCUploadFileTransfer 123 /*+ (void) initialize {124 [super initialize];125 if( ! fileTransferSignalsRegistered ) {126 IrssiLock();127 signal_add_last( "dcc connected", (SIGNAL_FUNC) MVFileTransferConnected );128 signal_add_last( "dcc transfer update", (SIGNAL_FUNC) MVFileTransferUpdate );129 signal_add_last( "dcc closed", (SIGNAL_FUNC) MVFileTransferClosed );130 signal_add_last( "dcc destroyed", (SIGNAL_FUNC) MVFileTransferDestroyed );131 signal_add_last( "dcc error connect", (SIGNAL_FUNC) MVFileTransferErrorConnect );132 signal_add_last( "dcc error file create", (SIGNAL_FUNC) MVFileTransferErrorFileCreate );133 signal_add_last( "dcc error file open", (SIGNAL_FUNC) MVFileTransferErrorFileOpen );134 signal_add_last( "dcc error send exists", (SIGNAL_FUNC) MVFileTransferErrorSendExists );135 IrssiUnlock();136 fileTransferSignalsRegistered = YES;137 }138 }139 140 88 + (id) transferWithSourceFile:(NSString *) path toUser:(MVChatUser *) user passively:(BOOL) passive { 141 89 NSURL *url = [NSURL URLWithString:@"http://colloquy.info/ip.php"]; 142 90 NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:3.]; 143 NSMutableData *result = [[ [NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL] mutableCopyWithZone:nil] autorelease];91 NSMutableData *result = [[NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL] mutableCopyWithZone:nil]; 144 92 [result appendBytes:"\0" length:1]; 145 146 if( [result length] > 1 ) { 147 IrssiLock(); 148 settings_set_str( "dcc_own_ip", [result bytes] ); 149 IrssiUnlock(); 150 } 151 152 IrssiLock(); 153 154 int queue = dcc_queue_new(); 155 NSString *source = [[path stringByStandardizingPath] copyWithZone:nil]; 156 157 char *tag = [(MVIRCChatConnection *)[user connection] _irssiConnection] -> tag; 158 159 if( ! passive ) dcc_queue_add( queue, DCC_QUEUE_NORMAL, [[user connection] encodedBytesWithString:[user nickname]], [source fileSystemRepresentation], tag, NULL ); 160 else dcc_queue_add_passive( queue, DCC_QUEUE_NORMAL, [[user connection] encodedBytesWithString:[user nickname]], [source fileSystemRepresentation], tag, NULL ); 161 162 dcc_queue_send_next( queue ); 163 164 DCC_REC *dcc = dcc_find_request( DCC_SEND_TYPE, [[user connection] encodedBytesWithString:[user nickname]], [[source lastPathComponent] fileSystemRepresentation] ); 165 166 MVIRCUploadFileTransfer *ret = [[[MVIRCUploadFileTransfer allocWithZone:nil] initWithDCCFileRecord:dcc toUser:user] autorelease]; 167 ret -> _source = [[source stringByStandardizingPath] copyWithZone:nil]; 168 ret -> _transferQueue = queue; 169 170 IrssiUnlock(); 171 172 return ret; 173 } 174 175 #pragma mark - 176 177 - (id) initWithDCCFileRecord:(void *) record toUser:(MVChatUser *) user { 178 if( ( self = [self initWithUser:user] ) ) 179 [self _setDCCFileRecord:record]; 180 return self; 181 } 182 93 94 [result release]; 95 96 MVIRCUploadFileTransfer *ret = [[MVIRCUploadFileTransfer allocWithZone:nil] initWithUser:user]; 97 [ret _setSource:path]; 98 99 return [ret autorelease]; 100 } 101 102 - (void) cancel { 103 [self _setStatus:MVFileTransferStoppedStatus]; 104 [_connection release]; 105 _connection = nil; 106 } 107 @end 108 109 #pragma mark - 110 111 @implementation MVIRCDownloadFileTransfer 183 112 - (void) dealloc { 184 [self _setDCCFileRecord:NULL]; 113 [(MVIRCChatConnection *)[[self user] connection] _removeFileTransfer:self]; 114 115 [_fileHandle synchronizeFile]; 116 [_fileHandle closeFile]; 117 118 [_connection release]; 119 [_fileHandle release]; 120 121 _connection = nil; 122 _connectionThread = nil; 123 _fileHandle = nil; 124 185 125 [super dealloc]; 186 126 } 187 127 188 #pragma mark - 189 190 - (BOOL) isPassive { 191 if( _passive || ! [self _DCCFileRecord] ) 192 return _passive; 193 194 @synchronized( self ) { 195 IrssiLock(); 196 if( [self _DCCFileRecord] ) 197 _passive = dcc_is_passive( [self _DCCFileRecord] ); 198 IrssiUnlock(); 199 200 return _passive; 201 } 202 } 203 204 #pragma mark - 205 206 - (unsigned long long) finalSize { 207 if( _finalSize || ! [self _DCCFileRecord] ) 208 return _finalSize; 209 210 @synchronized( self ) { 211 IrssiLock(); 212 if( [self _DCCFileRecord] ) 213 _finalSize = [self _DCCFileRecord] -> size; 214 IrssiUnlock(); 215 216 return _finalSize; 217 } 218 } 219 220 - (unsigned long long) transfered { 221 if( ! [self _DCCFileRecord] ) 222 return _transfered; 223 224 @synchronized( self ) { 225 IrssiLock(); 226 if( [self _DCCFileRecord] ) 227 _transfered = [self _DCCFileRecord] -> transfd; 228 IrssiUnlock(); 229 230 return _transfered; 231 } 232 } 233 234 #pragma mark - 235 236 - (NSDate *) startDate { 237 @synchronized( self ) { 238 if( _startDate || ! [self _DCCFileRecord] ) 239 return [[_startDate retain] autorelease]; 240 241 IrssiLock(); 242 if( [self _DCCFileRecord] && [self _DCCFileRecord] -> starttime ) 243 _startDate = [[NSDate dateWithTimeIntervalSince1970:[self _DCCFileRecord] -> starttime] retain]; 244 IrssiUnlock(); 245 246 return _startDate; 247 } 248 } 249 250 - (unsigned long long) startOffset { 251 if( _startOffset || ! [self _DCCFileRecord] ) 252 return _startOffset; 253 254 @synchronized( self ) { 255 IrssiLock(); 256 if( [self _DCCFileRecord] ) 257 _startOffset = [self _DCCFileRecord] -> skipped; 258 IrssiUnlock(); 259 260 return _startOffset; 261 } 262 } 263 264 #pragma mark - 265 266 - (NSHost *) host { 267 @synchronized( self ) { 268 if( _host || ! [self _DCCFileRecord] ) 269 return [[_host retain] autorelease]; 270 271 IrssiLock(); 272 if( [self _DCCFileRecord] ) 273 _host = [[NSHost hostWithAddress:[NSString stringWithUTF8String:[self _DCCFileRecord] -> addrstr]] retain]; 274 IrssiUnlock(); 275 276 return _host; 277 } 278 } 279 280 - (unsigned short) port { 281 if( _port || ! [self _DCCFileRecord] ) 282 return _port; 283 284 @synchronized( self ) { 285 IrssiLock(); 286 if( [self _DCCFileRecord] ) 287 _port = [self _DCCFileRecord] -> port; 288 IrssiUnlock(); 289 290 return _port; 291 } 292 } 293 294 #pragma mark - 128 - (void) reject { 129 if( _fileNameQuoted ) [[self user] sendSubcodeRequest:@"DCC" withArguments:[NSString stringWithFormat:@"REJECT \"%@\"", [self originalFileName]]]; 130 else [[self user] sendSubcodeRequest:@"DCC" withArguments:[NSString stringWithFormat:@"REJECT %@", [self originalFileName]]]; 131 } 295 132 296 133 - (void) cancel { 297 @synchronized( self ) { 298 // the Irssi thread callbacks check for this and call dcc_close then 299 [self _setStatus:MVFileTransferStoppedStatus]; 300 } 301 } */ 134 [self _setStatus:MVFileTransferStoppedStatus]; 135 [_connection release]; 136 _connection = nil; 137 } 138 139 - (void) acceptByResumingIfPossible:(BOOL) resume { 140 if( resume ) { 141 NSNumber *size = [[[NSFileManager defaultManager] fileAttributesAtPath:[self destination] traverseLink:YES] objectForKey:NSFileSize]; 142 BOOL fileExists = [[NSFileManager defaultManager] isWritableFileAtPath:[self destination]]; 143 144 if( fileExists && [size unsignedLongLongValue] < [self finalSize] ) { 145 if( [self isPassive] ) { 146 if( _fileNameQuoted ) [[self user] sendSubcodeRequest:@"DCC" withArguments:[NSString stringWithFormat:@"RESUME \"%@\" 0 %llu %lu", [self originalFileName], [size unsignedLongLongValue], _passiveId]]; 147 else [[self user] sendSubcodeRequest:@"DCC" withArguments:[NSString stringWithFormat:@"RESUME %@ 0 %llu %lu", [self originalFileName], [size unsignedLongLongValue], _passiveId]]; 148 } else { 149 if( _fileNameQuoted ) [[self user] sendSubcodeRequest:@"DCC" withArguments:[NSString stringWithFormat:@"RESUME \"%@\" %lu %llu", [self originalFileName], [self port], [size unsignedLongLongValue]]]; 150 else [[self user] sendSubcodeRequest:@"DCC" withArguments:[NSString stringWithFormat:@"RESUME %@ %lu %llu", [self originalFileName], [self port], [size unsignedLongLongValue]]]; 151 } 152 return; // we need to wait until we get an ACCEPT reply 153 } 154 } 155 156 [self _setupAndStart]; 157 } 158 159 #pragma mark - 160 161 - (void) socket:(AsyncSocket *) sock willDisconnectWithError:(NSError *) error { 162 NSLog(@"DCC willDisconnectWithError: %@", error ); 163 [self _setStatus:MVFileTransferErrorStatus]; 164 } 165 166 - (void) socketDidDisconnect:(AsyncSocket *) sock { 167 if( [self status] != MVFileTransferDoneStatus ) 168 [self _setStatus:MVFileTransferErrorStatus]; 169 170 [_fileHandle synchronizeFile]; 171 [_fileHandle closeFile]; 172 [_fileHandle release]; 173 _fileHandle = nil; 174 } 175 176 - (void) socket:(AsyncSocket *) sock didConnectToHost:(NSString *) host port:(UInt16) port { 177 [self _setStatus:MVFileTransferNormalStatus]; 178 179 [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVFileTransferStartedNotification object:self]; 180 181 unsigned long long progress = [self transfered]; 182 unsigned long long packet = DCCPacketSize; 183 if( ( progress + packet ) > [self finalSize] ) 184 packet = [self finalSize] - progress; 185 [_connection readDataToLength:packet withTimeout:-1. tag:0]; 186 } 187 188 - (void) socket:(AsyncSocket *) sock didReadData:(NSData *) data withTag:(long) tag { 189 unsigned long long progress = [self transfered] + [data length]; 190 [self _setTransfered:progress]; 191 192 // dcc only supports a 2 GB limit with these acknowledgment packets, we will acknowledge 193 // that we have all the bytes but keep reading if the file is over 2 GB 194 unsigned long progressToSend = htonl( progress & 0xffffffff ); 195 NSData *length = [[NSData allocWithZone:nil] initWithBytes:&progressToSend length:4]; 196 [_connection writeData:length withTimeout:-1 tag:0]; 197 [length release]; 198 199 [_fileHandle writeData:data]; 200 201 if( progress < [self finalSize] ) { 202 unsigned long long packet = DCCPacketSize; 203 if( ( progress + packet ) > [self finalSize] ) 204 packet = [self finalSize] - progress; 205 [_connection readDataToLength:packet withTimeout:-1. tag:0]; 206 } else { 207 [self _setStatus:MVFileTransferDoneStatus]; 208 [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVFileTransferFinishedNotification object:self]; 209 [_connection disconnect]; 210 } 211 } 212 213 #pragma mark - 214 215 - (void) _setupAndStart { 216 BOOL directory = NO; 217 BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[self destination] isDirectory:&directory]; 218 if( directory ) return; 219 if( ! fileExists ) [[NSData data] writeToFile:[self destination] atomically:NO]; 220 fileExists = [[NSFileManager defaultManager] isWritableFileAtPath:[self destination]]; 221 if( ! fileExists ) return; 222 223 [_fileHandle release]; 224 _fileHandle = [[NSFileHandle fileHandleForWritingAtPath:[self destination]] retain]; 225 if( ! _fileHandle ) return; 226 [_fileHandle truncateFileAtOffset:[self startOffset]]; 227 228 [_connection release]; 229 _connection = [[AsyncSocket allocWithZone:nil] initWithDelegate:self]; 230 231 if( ! _connectionThread ) { 232 [NSThread prepareForInterThreadMessages]; 233 [NSThread detachNewThreadSelector:@selector( _dccRunloop ) toTarget:self withObject:nil]; 234 while( ! _connectionThread ) sched_yield(); 235 } 236 237 [self performSelector:@selector( _connect ) inThread:_connectionThread]; 238 } 239 240 - (void) _connect { 241 if( ! [_connection connectToHost:[[self host] address] onPort:[self port] error:NULL] ) { 242 NSLog(@"can't connect to DCC" ); 243 return; 244 } 245 } 246 247 - (oneway void) _dccRunloop { 248 NSAutoreleasePool *pool = [[NSAutoreleasePool allocWithZone:nil] init]; 249 250 _connectionThread = [NSThread currentThread]; 251 [NSThread prepareForInterThreadMessages]; 252 [NSThread setThreadPriority:0.75]; 253 254 BOOL active = YES; 255 while( active && ( [self status] == MVFileTransferNormalStatus || [self status] == MVFileTransferHoldingStatus ) ) 256 active = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 257 258 if( [NSThread currentThread] == _connectionThread ) 259 _connectionThread = nil; 260 261 [pool release]; 262 } 302 263 @end 303 304 /* #pragma mark -305 306 @implementation MVIRCUploadFileTransfer (MVIRCUploadFileTransferPrivate)307 - (SEND_DCC_REC *) _DCCFileRecord {308 return _dcc;309 }310 311 - (void) _setDCCFileRecord:(FILE_DCC_REC *) record {312 @synchronized( self ) {313 IrssiLock();314 315 if( _dcc ) {316 MVFileTransferModuleData *data = MODULE_DATA( (DCC_REC *) _dcc );317 if( data ) data -> transfer = nil;318 MODULE_DATA_UNSET( (DCC_REC *) _dcc );319 }320 321 _dcc = record;322 323 if( record ) {324 MVFileTransferModuleData *data = g_new0( MVFileTransferModuleData, 1 );325 data -> transfer = self;326 MODULE_DATA_SET( (DCC_REC *) record, data );327 }328 329 IrssiUnlock();330 }331 }332 333 - (void) _destroying {334 @synchronized( self ) {335 // load the variables simply by calling the accessor336 [self isPassive];337 [self finalSize];338 [self transfered];339 [self port];340 [self startOffset];341 [self startDate];342 [self host];343 344 [self _setDCCFileRecord:NULL];345 }346 }347 @end348 349 #pragma mark -350 351 static void MVIRCDownloadFileTransferSpecifyPath( GET_DCC_REC *dcc ) {352 MVIRCDownloadFileTransfer *self = [MVFileTransfer _transferForDCCFileRecord:(FILE_DCC_REC *)dcc];353 if( ! self ) return;354 355 @synchronized( self ) {356 g_free_not_null( dcc -> file );357 dcc -> file = g_strdup( [[self destination] fileSystemRepresentation] );358 }359 }360 361 #pragma mark - */362 363 @implementation MVIRCDownloadFileTransfer364 /* + (void) initialize {365 [super initialize];366 static BOOL tooLate = NO;367 if( ! tooLate ) {368 IrssiLock();369 signal_add_last( "dcc get receive", (SIGNAL_FUNC) MVIRCDownloadFileTransferSpecifyPath );370 IrssiUnlock();371 tooLate = YES;372 }373 374 if( ! fileTransferSignalsRegistered ) {375 IrssiLock();376 signal_add_last( "dcc connected", (SIGNAL_FUNC) MVFileTransferConnected );377 signal_add_last( "dcc transfer update", (SIGNAL_FUNC) MVFileTransferUpdate );378 signal_add_last( "dcc closed", (SIGNAL_FUNC) MVFileTransferClosed );379 signal_add_last( "dcc destroyed", (SIGNAL_FUNC) MVFileTransferDestroyed );380 signal_add_last( "dcc error connect", (SIGNAL_FUNC) MVFileTransferErrorConnect );381 signal_add_last( "dcc error file create", (SIGNAL_FUNC) MVFileTransferErrorFileCreate );382 signal_add_last( "dcc error file open", (SIGNAL_FUNC) MVFileTransferErrorFileOpen );383 signal_add_last( "dcc error send exists", (SIGNAL_FUNC) MVFileTransferErrorSendExists );384 IrssiUnlock();385 fileTransferSignalsRegistered = YES;386 }387 }388 389 #pragma mark -390 391 - (id) initWithDCCFileRecord:(void *) record fromUser:(MVChatUser *) user {392 if( ( self = [self initWithUser:user] ) )393 [self _setDCCFileRecord:record];394 return self;395 }396 397 - (void) dealloc {398 [self _setDCCFileRecord:NULL];399 [super dealloc];400 }401 402 #pragma mark -403 404 - (BOOL) isPassive {405 if( _passive || ! [self _DCCFileRecord] )406 return _passive;407 408 @synchronized( self ) {409 IrssiLock();410 if( [self _DCCFileRecord] )411 _passive = dcc_is_passive( [self _DCCFileRecord] );412 IrssiUnlock();413 414 return _passive;415 }416 }417 418 #pragma mark -419 420 - (unsigned long long) finalSize {421 if( _finalSize || ! [self _DCCFileRecord] )422 return _finalSize;423 424 @synchronized( self ) {425 IrssiLock();426 if( [self _DCCFileRecord] )427 _finalSize = [self _DCCFileRecord] -> size;428 IrssiUnlock();429 430 return _finalSize;431 }432 }433 434 - (unsigned long long) transfered {435 if( ! [self _DCCFileRecord] ) return _transfered;436 437 @synchronized( self ) {438 IrssiLock();439 if( [self _DCCFileRecord] )440 _transfered = [self _DCCFileRecord] -> transfd;441 IrssiUnlock();442 443 return _transfered;444 }445 }446 447 #pragma mark -448 449 - (NSDate *) startDate {450 @synchronized( self ) {451 if( _startDate || ! [self _DCCFileRecord] )452 return [[_startDate retain] autorelease];453 454 IrssiLock();455 if( [self _DCCFileRecord] && [self _DCCFileRecord] -> starttime )456 _startDate = [[NSDate dateWithTimeIntervalSince1970:[self _DCCFileRecord] -> starttime] retain];457 IrssiUnlock();458 459 return _startDate;460 }461 }462 463 - (unsigned long long) startOffset {464 if( _startOffset || ! [self _DCCFileRecord] )465 return _startOffset;466 467 @synchronized( self ) {468 IrssiLock();469 if( [self _DCCFileRecord] )470 _startOffset = [self _DCCFileRecord] -> skipped;471 IrssiUnlock();472 473 return _startOffset;474 }475 }476 477 #pragma mark -478 479 - (NSHost *) host {480 @synchronized( self ) {481 if( _host || ! [self _DCCFileRecord] )482 return [[_host retain] autorelease];483 484 IrssiLock();485 if( [self _DCCFileRecord] )486 _host = [[NSHost hostWithAddress:[NSString stringWithUTF8String:[self _DCCFileRecord] -> addrstr]] retain];487 IrssiUnlock();488 489 return _host;490 }491 }492 493 - (unsigned short) port {494 if( _port || ! [self _DCCFileRecord] )495 return _port;496
