| 71 | | typedef struct { |
|---|
| 72 | | MVIRCChatConnection *connection; |
|---|
| 73 | | } MVIRCChatConnectionModuleData; |
|---|
| 74 | | |
|---|
| 75 | | // IRC error codes for most servers (some codes are not supported by all servers) |
|---|
| 76 | | #define ERR_NOSUCHNICK 401 // <nickname> :No such nick/channel |
|---|
| 77 | | #define ERR_NOSUCHSERVER 402 // <server name> :No such server |
|---|
| 78 | | #define ERR_NOSUCHCHANNEL 403 // <channel name> :No such channel |
|---|
| 79 | | #define ERR_CANNOTSENDTOCHAN 404 // <channel name> :Cannot send to channel |
|---|
| 80 | | #define ERR_TOOMANYCHANNELS 405 // <channel name> :You have joined too many channels |
|---|
| 81 | | #define ERR_WASNOSUCHNICK 406 // <nickname> :There was no such nickname |
|---|
| 82 | | #define ERR_TOOMANYTARGETS 407 // <target> :Duplicate recipients. No message delivered |
|---|
| 83 | | #define ERR_NOSUCHSERVICE 408 |
|---|
| 84 | | #define ERR_NOORIGIN 409 // :No origin specified |
|---|
| 85 | | #define ERR_CANNOTKNOCK 410 |
|---|
| 86 | | #define ERR_NORECIPIENT 411 // :No recipient given (<command>) |
|---|
| 87 | | #define ERR_NOTEXTTOSEND 412 // :No text to send |
|---|
| 88 | | #define ERR_NOTOPLEVEL 413 // <mask> :No toplevel domain specified |
|---|
| 89 | | #define ERR_WILDTOPLEVEL 414 // <mask> :Wildcard in toplevel domain |
|---|
| 90 | | #define ERR_SERVICESUP 415 |
|---|
| 91 | | |
|---|
| 92 | | #define ERR_UNKNOWNCOMMAND 421 // <command> :Unknown command |
|---|
| 93 | | #define ERR_NOMOTD 422 // :MOTD File is missing |
|---|
| 94 | | #define ERR_NOADMININFO 423 // <server> :No administrative info available |
|---|
| 95 | | #define ERR_FILEERROR 424 // :File error doing <file op> on <file> |
|---|
| 96 | | |
|---|
| 97 | | #define ERR_NONICKNAMEGIVEN 431 // :No nickname given |
|---|
| 98 | | #define ERR_ERRONEUSNICKNAME 432 // <nick> :Erroneus nickname |
|---|
| 99 | | #define ERR_NICKNAMEINUSE 433 // <nick> :Nickname is already in use |
|---|
| 100 | | #define ERR_SERVICENAMEINUSE 434 |
|---|
| 101 | | #define ERR_SERVICECONFUSED 435 |
|---|
| 102 | | #define ERR_NICKCOLLISION 436 // <nick> :Nickname collision KILL |
|---|
| 103 | | #define ERR_BANNICKCHANGE 437 |
|---|
| 104 | | #define ERR_NCHANGETOOFAST 438 |
|---|
| 105 | | #define ERR_TARGETTOOFAST 439 |
|---|
| 106 | | #define ERR_SERVICESDOWN 440 |
|---|
| 107 | | |
|---|
| 108 | | #define ERR_USERNOTINCHANNEL 441 // <nick> <channel> :They aren't on that channel |
|---|
| 109 | | #define ERR_NOTONCHANNEL 442 // <channel> :You're not on that channel |
|---|
| 110 | | #define ERR_USERONCHANNEL 443 // <user> <channel> :is already on channel |
|---|
| 111 | | #define ERR_NOLOGIN 444 // <user> :User not logged in |
|---|
| 112 | | #define ERR_SUMMONDISABLED 445 // :SUMMON has been disabled |
|---|
| 113 | | #define ERR_USERSDISABLED 446 // :USERS has been disabled |
|---|
| 114 | | |
|---|
| 115 | | #define ERR_NOTREGISTERED 451 // :You have not registered |
|---|
| 116 | | |
|---|
| 117 | | #define ERR_HOSTILENAME 455 |
|---|
| 118 | | |
|---|
| 119 | | #define ERR_NEEDMOREPARAMS 461 // <command> :Not enough parameters |
|---|
| 120 | | #define ERR_ALREADYREGISTRED 462 // :You may not reregister |
|---|
| 121 | | #define ERR_NOPERMFORHOST 463 // :Your host isn't among the privileged |
|---|
| 122 | | #define ERR_PASSWDMISMATCH 464 // :Password incorrect |
|---|
| 123 | | #define ERR_YOUREBANNEDCREEP 465 // :You are banned from this server |
|---|
| 124 | | #define ERR_YOUWILLBEBANNED 466 |
|---|
| 125 | | #define ERR_KEYSET 467 // <channel> :Channel key already set |
|---|
| 126 | | #define ERR_ONLYSERVERSCANCHANGE 468 |
|---|
| 127 | | |
|---|
| 128 | | #define ERR_CHANNELISFULL 471 // <channel> :Cannot join channel (+l) |
|---|
| 129 | | #define ERR_UNKNOWNMODE 472 // <char> :is unknown mode char to me |
|---|
| 130 | | #define ERR_INVITEONLYCHAN 473 // <channel> :Cannot join channel (+i) |
|---|
| 131 | | #define ERR_BANNEDFROMCHAN 474 // <channel> :Cannot join channel (+b) |
|---|
| 132 | | #define ERR_BADCHANNELKEY 475 // <channel> :Cannot join channel (+k) |
|---|
| 133 | | #define ERR_BADCHANMASK 476 |
|---|
| 134 | | #define ERR_NEEDREGGEDNICK 477 |
|---|
| 135 | | #define ERR_BANLISTFULL 478 |
|---|
| 136 | | #define ERR_NOPRIVILEGES 481 // :Permission Denied- You're not an IRC operator |
|---|
| 137 | | #define ERR_CHANOPRIVSNEEDED 482 // <channel> :You're not channel operator |
|---|
| 138 | | #define ERR_CANTKILLSERVER 483 // :You cant kill a server! |
|---|
| 139 | | #define ERR_CANTKICKOPER 484 // Undernet extension was ERR_ISCHANSERVICE |
|---|
| 140 | | #define ERR_CANTKICKADMIN 485 |
|---|
| 141 | | |
|---|
| 142 | | #define ERR_NOOPERHOST 491 // :No O-lines for your host |
|---|
| 143 | | #define ERR_NOSERVICEHOST 492 |
|---|
| 144 | | |
|---|
| 145 | | #define ERR_UMODEUNKNOWNFLAG 501 // :Unknown MODE flag |
|---|
| 146 | | #define ERR_USERSDONTMATCH 502 // :Cant change mode for other users |
|---|
| 147 | | |
|---|
| 148 | | #define ERR_SILELISTFULL 511 |
|---|
| 149 | | #define ERR_TOOMANYWATCH 512 |
|---|
| 150 | | #define ERR_NEEDPONG 513 |
|---|
| 151 | | |
|---|
| 152 | | #define ERR_LISTSYNTAX 521 |
|---|
| 153 | | |
|---|
| 468 | | static void MVChatUserWhois( IRC_SERVER_REC *server, const char *data ) { |
|---|
| 469 | | MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:(SERVER_REC *)server]; |
|---|
| 470 | | if( ! self ) return; |
|---|
| 471 | | |
|---|
| 472 | | char *nick = NULL, *username = NULL, *host = NULL, *realname = NULL; |
|---|
| 473 | | char *params = event_get_params( data, 6 | PARAM_FLAG_GETREST, NULL, &nick, &username, &host, NULL, &realname ); |
|---|
| 474 | | |
|---|
| 475 | | MVChatUser *user = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; |
|---|
| 476 | | [user _setServerOperator:NO]; // set these to off/nil now so we get the true values later in the WHOIS |
|---|
| 477 | | |
|---|
| 478 | | [user _setRealName:[self stringWithEncodedBytes:realname]]; |
|---|
| 479 | | [user _setUsername:[self stringWithEncodedBytes:username]]; |
|---|
| 480 | | [user _setAddress:[self stringWithEncodedBytes:host]]; |
|---|
| 481 | | |
|---|
| 482 | | g_free( params ); |
|---|
| 483 | | } |
|---|
| 484 | | |
|---|
| 485 | | static void MVChatUserServer( IRC_SERVER_REC *server, const char *data ) { |
|---|
| 486 | | MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:(SERVER_REC *)server]; |
|---|
| 487 | | if( ! self ) return; |
|---|
| 488 | | |
|---|
| 489 | | char *nick = NULL, *serv = NULL, *serverinfo = NULL; |
|---|
| 490 | | char *params = event_get_params( data, 4 | PARAM_FLAG_GETREST, NULL, &nick, &serv, &serverinfo ); |
|---|
| 491 | | |
|---|
| 492 | | MVChatUser *user = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; |
|---|
| 493 | | [user _setServerAddress:[self stringWithEncodedBytes:serv]]; |
|---|
| 494 | | |
|---|
| 495 | | g_free( params ); |
|---|
| 496 | | } |
|---|
| 497 | | |
|---|
| 498 | | static void MVChatUserChannels( IRC_SERVER_REC *server, const char *data ) { |
|---|
| 499 | | MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:(SERVER_REC *)server]; |
|---|
| 500 | | if( ! self ) return; |
|---|
| 501 | | |
|---|
| 502 | | char *nick = NULL, *chanlist = NULL; |
|---|
| 503 | | char *params = event_get_params( data, 3 | PARAM_FLAG_GETREST, NULL, &nick, &chanlist ); |
|---|
| 504 | | |
|---|
| 505 | | NSArray *chanArray = [[[self stringWithEncodedBytes:chanlist] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] componentsSeparatedByString:@" "]; |
|---|
| 506 | | NSMutableArray *results = [[NSMutableArray allocWithZone:nil] initWithCapacity:[chanArray count]]; |
|---|
| 507 | | NSEnumerator *enumerator = [chanArray objectEnumerator]; |
|---|
| 508 | | NSString *room = nil; |
|---|
| 509 | | |
|---|
| 510 | | NSCharacterSet *modeChars = [NSCharacterSet characterSetWithCharactersInString:@"@\%+ "]; |
|---|
| 511 | | while( ( room = [enumerator nextObject] ) ) { |
|---|
| 512 | | room = [room stringByTrimmingCharactersInSet:modeChars]; |
|---|
| 513 | | if( room ) [results addObject:room]; |
|---|
| 514 | | } |
|---|
| 515 | | |
|---|
| 516 | | if( [results count] ) { |
|---|
| 517 | | MVChatUser *user = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; |
|---|
| 518 | | [user setAttribute:results forKey:MVChatUserKnownRoomsAttribute]; |
|---|
| 519 | | } |
|---|
| 520 | | |
|---|
| 521 | | [results release]; |
|---|
| 522 | | g_free( params ); |
|---|
| 523 | | } |
|---|
| 524 | | |
|---|
| 525 | | static void MVChatUserIdentified( IRC_SERVER_REC *server, const char *data ) { |
|---|
| 526 | | MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:(SERVER_REC *)server]; |
|---|
| 527 | | if( ! self ) return; |
|---|
| 528 | | |
|---|
| 529 | | char *nick = NULL, *info = NULL; |
|---|
| 530 | | char *params = event_get_params( data, 3 | PARAM_FLAG_GETREST, NULL, &nick, &info ); |
|---|
| 531 | | |
|---|
| 532 | | if( info && strstr( info, "identified" ) ) { |
|---|
| 533 | | MVChatUser *user = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; |
|---|
| 534 | | [user _setIdentified:YES]; |
|---|
| 535 | | } |
|---|
| 536 | | |
|---|
| 537 | | g_free( params ); |
|---|
| 538 | | } |
|---|
| 539 | | |
|---|
| 540 | | static void MVChatUserOperator( IRC_SERVER_REC *server, const char *data ) { |
|---|
| 541 | | MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:(SERVER_REC *)server]; |
|---|
| 542 | | if( ! self ) return; |
|---|
| 543 | | |
|---|
| 544 | | char *nick = NULL; |
|---|
| 545 | | char *params = event_get_params( data, 2, NULL, &nick ); |
|---|
| 546 | | |
|---|
| 547 | | MVChatUser *user = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; |
|---|
| 548 | | [user _setServerOperator:YES]; |
|---|
| 549 | | |
|---|
| 550 | | g_free( params ); |
|---|
| 551 | | } |
|---|
| 552 | | |
|---|
| 553 | | static void MVChatUserIdle( IRC_SERVER_REC *server, const char *data ) { |
|---|
| 554 | | MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:(SERVER_REC *)server]; |
|---|
| 555 | | if( ! self ) return; |
|---|
| 556 | | |
|---|
| 557 | | char *nick = NULL, *idle = NULL, *connected = NULL; |
|---|
| 558 | | char *params = event_get_params( data, 4, NULL, &nick, &idle, &connected ); |
|---|
| 559 | | |
|---|
| 560 | | MVChatUser *user = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; |
|---|
| 561 | | [user _setIdleTime:[[self stringWithEncodedBytes:idle] intValue]]; |
|---|
| 562 | | if( [[self stringWithEncodedBytes:connected] intValue] > 631138520 ) // prevent showing 34+ years connected time, this makes sure it is a viable date |
|---|
| 563 | | [user _setDateConnected:[NSDate dateWithTimeIntervalSince1970:[[self stringWithEncodedBytes:connected] intValue]]]; |
|---|
| 564 | | else [user _setDateConnected:nil]; |
|---|
| 565 | | |
|---|
| 566 | | g_free( params ); |
|---|
| 567 | | } |
|---|
| 568 | | |
|---|
| 569 | | static void MVChatUserWhoisComplete( IRC_SERVER_REC *server, const char *data ) { |
|---|
| 570 | | if( data ) { |
|---|
| 571 | | MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:(SERVER_REC *)server]; |
|---|
| 572 | | if( ! self ) return; |
|---|
| 573 | | |
|---|
| 574 | | char *nick = NULL; |
|---|
| 575 | | char *params = event_get_params( data, 2, NULL, &nick ); |
|---|
| 576 | | |
|---|
| 577 | | MVChatUser *user = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; |
|---|
| 578 | | [user _setDateUpdated:[NSDate date]]; |
|---|
| 579 | | |
|---|
| 580 | | if( [user status] != MVChatUserAwayStatus ) [user _setStatus:MVChatUserAvailableStatus]; |
|---|
| 581 | | |
|---|
| 582 | | NSNotification *note = [NSNotification notificationWithName:MVChatUserInformationUpdatedNotification object:user userInfo:nil]; |
|---|
| 583 | | [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:note]; |
|---|
| 584 | | |
|---|
| 585 | | g_free( params ); |
|---|
| 586 | | } |
|---|
| 587 | | } |
|---|
| 588 | | |
|---|
| 589 | | #pragma mark - |
|---|
| 590 | | |
|---|
| | 1587 | |
|---|
| | 1588 | #pragma mark - |
|---|
| | 1589 | #pragma mark WHOIS Replies |
|---|
| | 1590 | |
|---|
| | 1591 | - (void) _handle311WithParameters:(NSArray *) parameters fromSender:(id) sender { // RPL_WHOISUSER |
|---|
| | 1592 | if( [parameters count] == 6 ) { |
|---|
| | 1593 | MVChatUser *user = [self chatUserWithUniqueIdentifier:[parameters objectAtIndex:1]]; |
|---|
| | 1594 | [user _setServerOperator:NO]; // set these to NO now so we get the true values later in the WHOIS |
|---|
| | 1595 | [user _setUsername:[parameters objectAtIndex:2]]; |
|---|
| | 1596 | [user _setAddress:[parameters objectAtIndex:3]]; |
|---|
| | 1597 | NSString *realName = [[NSString allocWithZone:nil] initWithData:[parameters objectAtIndex:5] encoding:[self encoding]]; |
|---|
| | 1598 | [user _setRealName:realName]; |
|---|
| | 1599 | [realName release]; |
|---|
| | 1600 | } |
|---|
| | 1601 | } |
|---|
| | 1602 | |
|---|
| | 1603 | - (void) _handle312WithParameters:(NSArray *) parameters fromSender:(id) sender { // RPL_WHOISSERVER |
|---|
| | 1604 | if( [parameters count] >= 3 ) { |
|---|
| | 1605 | MVChatUser *user = [self chatUserWithUniqueIdentifier:[parameters objectAtIndex:1]]; |
|---|
| | 1606 | [user _setServerAddress:[parameters objectAtIndex:2]]; |
|---|
| | 1607 | } |
|---|
| | 1608 | } |
|---|
| | 1609 | |
|---|
| | 1610 | - (void) _handle313WithParameters:(NSArray *) parameters fromSender:(id) sender { // RPL_WHOISOPERATOR |
|---|
| | 1611 | if( [parameters count] >= 2 ) { |
|---|
| | 1612 | MVChatUser *user = [self chatUserWithUniqueIdentifier:[parameters objectAtIndex:1]]; |
|---|
| | 1613 | [user _setServerOperator:YES]; |
|---|
| | 1614 | } |
|---|
| | 1615 | } |
|---|
| | 1616 | |
|---|
| | 1617 | - (void) _handle317WithParameters:(NSArray *) parameters fromSender:(id) sender { // RPL_WHOISIDLE |
|---|
| | 1618 | if( [parameters count] >= 3 ) { |
|---|
| | 1619 | MVChatUser *user = [self chatUserWithUniqueIdentifier:[parameters objectAtIndex:1]]; |
|---|
| | 1620 | [user _setIdleTime:[[parameters objectAtIndex:2] intValue]]; |
|---|
| | 1621 | [user _setDateConnected:nil]; |
|---|
| | 1622 | |
|---|
| | 1623 | // parameter 4 is connection time on some servers |
|---|
| | 1624 | // prevent showing 34+ years connected time, this makes sure it is a viable date |
|---|
| | 1625 | if( [parameters count] >= 4 && [[parameters objectAtIndex:3] intValue] > 631138520 ) |
|---|
| | 1626 | [user _setDateConnected:[NSDate dateWithTimeIntervalSince1970:[[parameters objectAtIndex:3] intValue]]]; |
|---|
| | 1627 | } |
|---|
| | 1628 | } |
|---|
| | 1629 | |
|---|
| | 1630 | - (void) _handle318WithParameters:(NSArray *) parameters fromSender:(id) sender { // RPL_ENDOFWHOIS |
|---|
| | 1631 | if( [parameters count] >= 2 ) { |
|---|
| | 1632 | MVChatUser *user = [self chatUserWithUniqueIdentifier:[parameters objectAtIndex:1]]; |
|---|
| | 1633 | [user _setDateUpdated:[NSDate date]]; |
|---|
| | 1634 | |
|---|
| | 1635 | if( [user status] != MVChatUserAwayStatus ) [user _setStatus:MVChatUserAvailableStatus]; |
|---|
| | 1636 | |
|---|
| | 1637 | [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVChatUserInformationUpdatedNotification object:user userInfo:nil]; |
|---|
| | 1638 | } |
|---|
| | 1639 | } |
|---|
| | 1640 | |
|---|
| | 1641 | - (void) _handle319WithParameters:(NSArray *) parameters fromSender:(id) sender { // RPL_WHOISCHANNELS |
|---|
| | 1642 | if( [parameters count] == 3 ) { |
|---|
| | 1643 | NSString *rooms = [[NSString allocWithZone:nil] initWithData:[parameters objectAtIndex:2] encoding:[self encoding]]; |
|---|
| | 1644 | NSArray *chanArray = [[rooms stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] componentsSeparatedByString:@" "]; |
|---|
| | 1645 | NSMutableArray *results = [[NSMutableArray allocWithZone:nil] initWithCapacity:[chanArray count]]; |
|---|
| | 1646 | NSEnumerator *enumerator = [chanArray objectEnumerator]; |
|---|
| | 1647 | NSString *room = nil; |
|---|
| | 1648 | |
|---|
| | 1649 | NSCharacterSet *modeChars = [NSCharacterSet characterSetWithCharactersInString:@"@\%+ "]; |
|---|
| | 1650 | while( ( room = [enumerator nextObject] ) ) { |
|---|
| | 1651 | room = [room stringByTrimmingCharactersInSet:modeChars]; |
|---|
| | 1652 | if( room ) [results addObject:room]; |
|---|
| | 1653 | } |
|---|
| | 1654 | |
|---|
| | 1655 | if( [results count] ) { |
|---|
| | 1656 | MVChatUser *user = [self chatUserWithUniqueIdentifier:[parameters objectAtIndex:1]]; |
|---|
| | 1657 | [user setAttribute:results forKey:MVChatUserKnownRoomsAttribute]; |
|---|
| | 1658 | } |
|---|
| | 1659 | |
|---|
| | 1660 | [rooms release]; |
|---|
| | 1661 | [results release]; |
|---|
| | 1662 | } |
|---|
| | 1663 | } |
|---|
| | 1664 | |
|---|
| | 1665 | - (void) _handle320WithParameters:(NSArray *) parameters fromSender:(id) sender { // RPL_WHOISIDENTIFIED |
|---|
| | 1666 | if( [parameters count] == 3 ) { |
|---|
| | 1667 | NSString *comment = [[NSString allocWithZone:nil] initWithData:[parameters objectAtIndex:2] encoding:[self encoding]]; |
|---|
| | 1668 | if( [comment rangeOfString:@"identified" options:NSCaseInsensitiveSearch].location != NSNotFound ) { |
|---|
| | 1669 | MVChatUser *user = [self chatUserWithUniqueIdentifier:[parameters objectAtIndex:1]]; |
|---|
| | 1670 | [user _setIdentified:YES]; |
|---|
| | 1671 | } |
|---|
| | 1672 | [comment release]; |
|---|
| | 1673 | } |
|---|
| | 1674 | } |
|---|