static void irc_cmd_whowas( irc_t *irc, char **cmd ) { /* For some reason irssi tries a whowas when whois fails. We can ignore this, but then the user never gets a "user not found" message from irssi which is a bit annoying. So just respond with not-found and irssi users will get better error messages */ irc_send_num( irc, 406, "%s :Nick does not exist", cmd[1] ); irc_send_num( irc, 369, "%s :End of WHOWAS", cmd[1] ); }
static gboolean bee_irc_user_status(bee_t *bee, bee_user_t *bu, bee_user_t *old) { irc_t *irc = bee->ui_data; irc_user_t *iu = bu->ui_data; /* Do this outside the if below since away state can change without the online state changing. */ iu->flags &= ~IRC_USER_AWAY; if (bu->flags & BEE_USER_AWAY || !(bu->flags & BEE_USER_ONLINE)) { iu->flags |= IRC_USER_AWAY; } if ((bu->flags & BEE_USER_ONLINE) != (old->flags & BEE_USER_ONLINE)) { if (bu->flags & BEE_USER_ONLINE) { if (g_hash_table_lookup(irc->watches, iu->key)) { irc_send_num(irc, 600, "%s %s %s %d :%s", iu->nick, iu->user, iu->host, (int) time(NULL), "logged online"); } } else { if (g_hash_table_lookup(irc->watches, iu->key)) { irc_send_num(irc, 601, "%s %s %s %d :%s", iu->nick, iu->user, iu->host, (int) time(NULL), "logged offline"); } /* Send a QUIT since those will also show up in any query windows the user may have, plus it's only one QUIT instead of possibly many (in case of multiple control chans). If there's a channel that shows offline people, a JOIN will follow. */ if (set_getbool(&bee->set, "offline_user_quits")) { irc_user_quit(iu, "Leaving..."); } } } /* Reset this one since the info may have changed. */ iu->away_reply_timeout = 0; bee_irc_channel_update(irc, NULL, iu); /* If away-notify enabled, send status updates when: * Away or Online state changes * Status changes (e.g. "Away" to "Mobile") * Status message changes */ if ((irc->caps & CAP_AWAY_NOTIFY) && ((bu->flags & BEE_USER_AWAY) != (old->flags & BEE_USER_AWAY) || (bu->flags & BEE_USER_ONLINE) != (old->flags & BEE_USER_ONLINE) || (g_strcmp0(bu->status, old->status) != 0) || (g_strcmp0(bu->status_msg, old->status_msg) != 0))) { irc_send_away_notify(iu); } return TRUE; }
static void irc_cmd_privmsg( irc_t *irc, char **cmd ) { irc_channel_t *ic; irc_user_t *iu; if( !cmd[2] ) { irc_send_num( irc, 412, ":No text to send" ); return; } /* Don't treat CTCP actions as real CTCPs, just convert them right now. */ if( g_strncasecmp( cmd[2], "\001ACTION", 7 ) == 0 ) { cmd[2] += 4; memcpy( cmd[2], "/me", 3 ); if( cmd[2][strlen(cmd[2])-1] == '\001' ) cmd[2][strlen(cmd[2])-1] = '\0'; } if( irc_channel_name_ok( cmd[1] ) && ( ic = irc_channel_by_name( irc, cmd[1] ) ) ) { if( cmd[2][0] == '\001' ) { /* CTCPs to channels? Nah. Maybe later. */ } else if( ic->f->privmsg ) ic->f->privmsg( ic, cmd[2] ); } else if( ( iu = irc_user_by_name( irc, cmd[1] ) ) ) { if( cmd[2][0] == '\001' ) { char **ctcp; if( iu->f->ctcp == NULL ) return; if( cmd[2][strlen(cmd[2])-1] == '\001' ) cmd[2][strlen(cmd[2])-1] = '\0'; ctcp = split_command_parts( cmd[2] + 1 ); iu->f->ctcp( iu, ctcp ); } else if( iu->f->privmsg ) { iu->last_channel = NULL; iu->f->privmsg( iu, cmd[2] ); } } else { irc_send_num( irc, 401, "%s :No such nick/channel", cmd[1] ); } }
void irc_send_motd(irc_t *irc) { char motd[2048]; ssize_t len; int fd; fd = open(global.conf->motdfile, O_RDONLY); if (fd == -1 || (len = read(fd, motd, sizeof(motd) - 1)) <= 0) { irc_send_num(irc, 422, ":We don't need MOTDs."); } else { char linebuf[80]; char *add = "", max, *in; in = motd; motd[len] = '\0'; linebuf[79] = len = 0; max = sizeof(linebuf) - 1; irc_send_num(irc, 375, ":- %s Message Of The Day - ", irc->root->host); while ((linebuf[len] = *(in++))) { if (linebuf[len] == '\n' || len == max) { linebuf[len] = 0; irc_send_num(irc, 372, ":- %s", linebuf); len = 0; } else if (linebuf[len] == '%') { linebuf[len] = *(in++); if (linebuf[len] == 'h') { add = irc->root->host; } else if (linebuf[len] == 'v') { add = BITLBEE_VERSION; } else if (linebuf[len] == 'n') { add = irc->user->nick; } else if (linebuf[len] == '\0') { in--; } else { add = "%"; } strncpy(linebuf + len, add, max - len); while (linebuf[++len]) { ; } } else if (len < max) { len++; } } irc_send_num(irc, 376, ":End of MOTD"); } if (fd != -1) { close(fd); } }
void irc_send_login(irc_t *irc) { irc_send_num(irc, 1, ":Welcome to the %s gateway, %s", PACKAGE, irc->user->nick); irc_send_num(irc, 2, ":Host %s is running %s %s %s/%s.", irc->root->host, PACKAGE, BITLBEE_VERSION, ARCH, CPU); irc_send_num(irc, 3, ":%s", IRCD_INFO); irc_send_num(irc, 4, "%s %s %s %s", irc->root->host, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES); irc_send_num(irc, 5, "PREFIX=(ohv)@%%+ CHANTYPES=%s CHANMODES=,,,%s NICKLEN=%d CHANNELLEN=%d " "NETWORK=BitlBee SAFELIST CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 " "FLOOD=0/9999 :are supported by this server", CTYPES, CMODES, MAX_NICK_LENGTH - 1, MAX_NICK_LENGTH - 1); irc_send_motd(irc); }
static void irc_cmd_oper_hack( irc_t *irc, char **cmd ) { char *password = g_strjoinv( " ", cmd + 2 ); /* /OPER can now also be used to enter IM/identify passwords without echoing. It's a hack but the extra password security is worth it. */ if( irc->status & OPER_HACK_ACCOUNT_ADD ) { account_t *a; for( a = irc->b->accounts; a; a = a->next ) if( strcmp( a->pass, PASSWORD_PENDING ) == 0 ) { set_setstr( &a->set, "password", password ); irc_rootmsg( irc, "Password added to IM account " "%s", a->tag ); /* The IRC client may expect this. 491 suggests the OPER password was wrong, so the client won't expect a +o. It may however repeat the password prompt. We'll see. */ irc_send_num( irc, 491, ":Password added to IM account " "%s", a->tag ); } } else if( irc->status & OPER_HACK_IDENTIFY ) { char *send_cmd[] = { "identify", password, NULL, NULL }; irc->status &= ~OPER_HACK_IDENTIFY; if( irc->status & OPER_HACK_IDENTIFY_NOLOAD ) { send_cmd[1] = "-noload"; send_cmd[2] = password; } else if( irc->status & OPER_HACK_IDENTIFY_FORCE ) { send_cmd[1] = "-force"; send_cmd[2] = password; } irc_send_num( irc, 491, ":Trying to identify" ); root_command( irc, send_cmd ); } else if( irc->status & OPER_HACK_REGISTER ) { char *send_cmd[] = { "register", password, NULL }; irc_send_num( irc, 491, ":Trying to identify" ); root_command( irc, send_cmd ); } irc->status &= ~OPER_HACK_ANY; g_free( password ); }
static void irc_cmd_pass( irc_t *irc, char **cmd ) { if( irc->status & USTATUS_LOGGED_IN ) { char *send_cmd[] = { "identify", cmd[1], NULL }; /* We're already logged in, this client seems to send the PASS command last. (Possibly it won't send it at all if it turns out we don't require it, which will break this feature.) Try to identify using the given password. */ root_command( irc, send_cmd ); return; } /* Handling in pre-logged-in state, first see if this server is password-protected: */ else if( global.conf->auth_pass && ( strncmp( global.conf->auth_pass, "md5:", 4 ) == 0 ? md5_verify_password( cmd[1], global.conf->auth_pass + 4 ) == 0 : strcmp( cmd[1], global.conf->auth_pass ) == 0 ) ) { irc->status |= USTATUS_AUTHORIZED; irc_check_login( irc ); } else if( global.conf->auth_pass ) { irc_send_num( irc, 464, ":Incorrect password" ); } else { /* Remember the password and try to identify after USER/NICK. */ irc_setpass( irc, cmd[1] ); irc_check_login( irc ); } }
static void irc_cmd_watch( irc_t *irc, char **cmd ) { int i; /* Obviously we could also mark a user structure as being watched, but what if the WATCH command is sent right after connecting? The user won't exist yet then... */ for( i = 1; cmd[i]; i ++ ) { char *nick; irc_user_t *iu; if( !cmd[i][0] || !cmd[i][1] ) break; nick = g_strdup( cmd[i] + 1 ); nick_lc( nick ); iu = irc_user_by_name( irc, nick ); if( cmd[i][0] == '+' ) { if( !g_hash_table_lookup( irc->watches, nick ) ) g_hash_table_insert( irc->watches, nick, nick ); if( iu && iu->bu && iu->bu->flags & BEE_USER_ONLINE ) irc_send_num( irc, 604, "%s %s %s %d :%s", iu->nick, iu->user, iu->host, (int) time( NULL ), "is online" ); else irc_send_num( irc, 605, "%s %s %s %d :%s", nick, "*", "*", (int) time( NULL ), "is offline" ); } else if( cmd[i][0] == '-' ) { gpointer okey, ovalue; if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) ) { g_hash_table_remove( irc->watches, okey ); g_free( okey ); irc_send_num( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" ); } } } }
static void irc_cmd_part( irc_t *irc, char **cmd ) { irc_channel_t *ic; if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL ) { irc_send_num( irc, 403, "%s :No such channel", cmd[1] ); } else if( irc_channel_del_user( ic, irc->user, IRC_CDU_PART, cmd[2] ) ) { if( ic->f->part ) ic->f->part( ic, NULL ); } else { irc_send_num( irc, 442, "%s :You're not on that channel", cmd[1] ); } }
static void irc_cmd_topic( irc_t *irc, char **cmd ) { irc_channel_t *ic = irc_channel_by_name( irc, cmd[1] ); const char *new = cmd[2]; if( ic == NULL ) { irc_send_num( irc, 403, "%s :No such channel", cmd[1] ); } else if( new ) { if( ic->f->topic == NULL ) irc_send_num( irc, 482, "%s :Can't change this channel's topic", ic->name ); else if( ic->f->topic( ic, new ) ) irc_send_topic( ic, TRUE ); } else {
static void irc_cmd_whois( irc_t *irc, char **cmd ) { char *nick = cmd[1]; irc_user_t *iu = irc_user_by_name( irc, nick ); if( iu ) irc_send_whois( iu ); else irc_send_num( irc, 401, "%s :Nick does not exist", nick ); }
static void irc_cmd_oper( irc_t *irc, char **cmd ) { /* Very non-standard evil but useful/secure hack, see below. */ if( irc->status & OPER_HACK_ANY ) return irc_cmd_oper_hack( irc, cmd ); if( global.conf->oper_pass && ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ? md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 : strcmp( cmd[2], global.conf->oper_pass ) == 0 ) ) { irc_umode_set( irc, "+o", 1 ); irc_send_num( irc, 381, ":Password accepted" ); } else { irc_send_num( irc, 491, ":Incorrect password" ); } }
static void irc_cmd_ison( irc_t *irc, char **cmd ) { char buff[IRC_MAX_LINE]; int lenleft, i; buff[0] = '\0'; /* [SH] Leave room for : and \0 */ lenleft = IRC_MAX_LINE - 2; for( i = 1; cmd[i]; i ++ ) { char *this, *next; this = cmd[i]; while( *this ) { irc_user_t *iu; if( ( next = strchr( this, ' ' ) ) ) *next = 0; if( ( iu = irc_user_by_name( irc, this ) ) && iu->bu && iu->bu->flags & BEE_USER_ONLINE ) { lenleft -= strlen( iu->nick ) + 1; if( lenleft < 0 ) break; strcat( buff, iu->nick ); strcat( buff, " " ); } if( next ) { *next = ' '; this = next + 1; } else { break; } } /* *sigh* */ if( lenleft < 0 ) break; } if( strlen( buff ) > 0 ) buff[strlen(buff)-1] = '\0'; irc_send_num( irc, 303, ":%s", buff ); }
static gboolean bee_irc_user_status( bee_t *bee, bee_user_t *bu, bee_user_t *old ) { irc_t *irc = bee->ui_data; irc_user_t *iu = bu->ui_data; /* Do this outside the if below since away state can change without the online state changing. */ iu->flags &= ~IRC_USER_AWAY; if( bu->flags & BEE_USER_AWAY || !( bu->flags & BEE_USER_ONLINE ) ) iu->flags |= IRC_USER_AWAY; if( ( bu->flags & BEE_USER_ONLINE ) != ( old->flags & BEE_USER_ONLINE ) ) { if( bu->flags & BEE_USER_ONLINE ) { if( g_hash_table_lookup( irc->watches, iu->key ) ) irc_send_num( irc, 600, "%s %s %s %d :%s", iu->nick, iu->user, iu->host, (int) time( NULL ), "logged online" ); } else { if( g_hash_table_lookup( irc->watches, iu->key ) ) irc_send_num( irc, 601, "%s %s %s %d :%s", iu->nick, iu->user, iu->host, (int) time( NULL ), "logged offline" ); /* Send a QUIT since those will also show up in any query windows the user may have, plus it's only one QUIT instead of possibly many (in case of multiple control chans). If there's a channel that shows offline people, a JOIN will follow. */ if( set_getbool( &bee->set, "offline_user_quits" ) ) irc_user_quit( iu, "Leaving..." ); } } /* Reset this one since the info may have changed. */ iu->away_reply_timeout = 0; bee_irc_channel_update( irc, NULL, iu ); return TRUE; }
static void irc_cmd_invite( irc_t *irc, char **cmd ) { irc_channel_t *ic; irc_user_t *iu; if( ( iu = irc_user_by_name( irc, cmd[1] ) ) == NULL ) { irc_send_num( irc, 401, "%s :No such nick", cmd[1] ); return; } else if( ( ic = irc_channel_by_name( irc, cmd[2] ) ) == NULL ) { irc_send_num( irc, 403, "%s :No such channel", cmd[2] ); return; } if( !ic->f->invite ) irc_send_num( irc, 482, "%s :Can't invite people here", cmd[2] ); else if( ic->f->invite( ic, iu ) ) irc_send_num( irc, 341, "%s %s", iu->nick, ic->name ); }
static void irc_cmd_mode( irc_t *irc, char **cmd ) { if( irc_channel_name_ok( cmd[1] ) ) { irc_channel_t *ic; if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL ) irc_send_num( irc, 403, "%s :No such channel", cmd[1] ); else if( cmd[2] ) { if( *cmd[2] == '+' || *cmd[2] == '-' ) irc_send_num( irc, 477, "%s :Can't change channel modes", cmd[1] ); else if( *cmd[2] == 'b' ) irc_send_num( irc, 368, "%s :No bans possible", cmd[1] ); } else irc_send_num( irc, 324, "%s +%s", cmd[1], ic->mode ); } else { if( nick_cmp( cmd[1], irc->user->nick ) == 0 ) { if( cmd[2] ) irc_umode_set( irc, cmd[2], 0 ); else irc_send_num( irc, 221, "+%s", irc->umode ); } else irc_send_num( irc, 502, ":Don't touch their modes" ); } }
static void irc_cmd_nick( irc_t *irc, char **cmd ) { irc_user_t *iu; if( ( iu = irc_user_by_name( irc, cmd[1] ) ) && iu != irc->user ) { irc_send_num( irc, 433, "%s :This nick is already in use", cmd[1] ); } else if( !nick_ok( cmd[1] ) ) { /* [SH] Invalid characters. */ irc_send_num( irc, 432, "%s :This nick contains invalid characters", cmd[1] ); } else if( irc->status & USTATUS_LOGGED_IN ) { /* WATCH OUT: iu from the first if reused here to check if the new nickname is the same (other than case, possibly). If it is, no need to reset identify-status. */ if( ( irc->status & USTATUS_IDENTIFIED ) && iu != irc->user ) { irc_setpass( irc, NULL ); irc->status &= ~USTATUS_IDENTIFIED; irc_umode_set( irc, "-R", 1 ); irc_rootmsg( irc, "Changing nicks resets your identify status. " "Re-identify or register a new account if you want " "your configuration to be saved. See \x02help " "nick_changes\x02." ); } if( strcmp( cmd[1], irc->user->nick ) != 0 ) irc_user_set_nick( irc->user, cmd[1] ); } else { g_free( irc->user->nick ); irc->user->nick = g_strdup( cmd[1] ); irc_check_login( irc ); } }
static void irc_cmd_notice( irc_t *irc, char **cmd ) { if( !cmd[2] ) { irc_send_num( irc, 412, ":No text to send" ); return; } /* At least for now just echo. IIRC some IRC clients use self-notices for lag checks, so try to support that. */ if( nick_cmp( cmd[1], irc->user->nick ) == 0 ) irc_send_msg( irc->user, "NOTICE", irc->user->nick, cmd[2], NULL ); }
static void irc_cmd_nick( irc_t *irc, char **cmd ) { irc_user_t *iu; if( ( iu = irc_user_by_name( irc, cmd[1] ) ) && iu != irc->user ) { irc_send_num( irc, 433, "%s :This nick is already in use", cmd[1] ); } else if( !nick_ok( cmd[1] ) ) { /* [SH] Invalid characters. */ irc_send_num( irc, 432, "%s :This nick contains invalid characters", cmd[1] ); } else if( irc->status & USTATUS_LOGGED_IN ) { if( irc->status & USTATUS_IDENTIFIED ) { irc_setpass( irc, NULL ); irc->status &= ~USTATUS_IDENTIFIED; irc_umode_set( irc, "-R", 1 ); irc_usermsg( irc, "Changing nicks resets your identify status. " "Re-identify or register a new account if you want " "your configuration to be saved. See \x02help " "nick_changes\x02." ); } irc_user_set_nick( irc->user, cmd[1] ); } else { g_free( irc->user->nick ); irc->user->nick = g_strdup( cmd[1] ); irc_check_login( irc ); } }
static void cmd_register(irc_t *irc, char **cmd) { char s[16]; if (global.conf->authmode == AUTHMODE_REGISTERED) { irc_rootmsg(irc, "This server does not allow registering new accounts"); return; } if (cmd[1] == NULL) { irc_rootmsg(irc, "About to register, use /OPER to enter the password"); irc->status |= OPER_HACK_REGISTER; return; } switch (storage_save(irc, cmd[1], FALSE)) { case STORAGE_ALREADY_EXISTS: irc_rootmsg(irc, "Nick is already registered"); break; case STORAGE_OK: irc_rootmsg(irc, "Account successfully created"); irc_setpass(irc, cmd[1]); irc->status |= USTATUS_IDENTIFIED; irc_umode_set(irc, "+R", 1); if (irc->caps & CAP_SASL) { irc_user_t *iu = irc->user; irc_send_num(irc, 900, "%s!%s@%s %s :You are now logged in as %s", iu->nick, iu->user, iu->host, iu->nick, iu->nick); } /* Set this var now, or anyone who logs in to his/her newly created account for the first time gets the whatsnew story. */ g_snprintf(s, sizeof(s), "%d", BITLBEE_VERSION_CODE); set_setstr(&irc->b->set, "last_version", s); break; default: irc_rootmsg(irc, "Error registering"); break; } }
static void irc_cmd_who( irc_t *irc, char **cmd ) { char *channel = cmd[1]; irc_channel_t *ic; irc_user_t *iu; if( !channel || *channel == '0' || *channel == '*' || !*channel ) irc_send_who( irc, irc->users, "**" ); else if( ( ic = irc_channel_by_name( irc, channel ) ) ) irc_send_who( irc, ic->users, channel ); else if( ( iu = irc_user_by_name( irc, channel ) ) ) { /* Tiny hack! */ GSList *l = g_slist_append( NULL, iu ); irc_send_who( irc, l, channel ); g_slist_free( l ); } else irc_send_num( irc, 403, "%s :No such channel", channel ); }
static void irc_cmd_userhost( irc_t *irc, char **cmd ) { int i; /* [TV] Usable USERHOST-implementation according to RFC1459. Without this, mIRC shows an error while connecting, and the used way of rejecting breaks standards. */ for( i = 1; cmd[i]; i ++ ) { irc_user_t *iu = irc_user_by_name( irc, cmd[i] ); if( iu ) irc_send_num( irc, 302, ":%s=%c%s@%s", iu->nick, irc_user_get_away( iu ) ? '-' : '+', iu->user, iu->host ); } }
static void cmd_identify(irc_t *irc, char **cmd) { storage_status_t status; gboolean load = TRUE; char *password = cmd[1]; if (irc->status & USTATUS_IDENTIFIED) { irc_rootmsg(irc, "You're already logged in."); return; } if (cmd[1] == NULL) { } else if (strncmp(cmd[1], "-no", 3) == 0) { load = FALSE; password = cmd[2]; if (password == NULL) { irc->status |= OPER_HACK_IDENTIFY_NOLOAD; } } else if (strncmp(cmd[1], "-force", 6) == 0) { password = cmd[2]; if (password == NULL) { irc->status |= OPER_HACK_IDENTIFY_FORCE; } } else if (irc->b->accounts != NULL) { irc_rootmsg(irc, "You're trying to identify yourself, but already have " "at least one IM account set up. " "Use \x02identify -noload\x02 or \x02identify -force\x02 " "instead (see \x02help identify\x02)."); return; } if (password == NULL) { irc_rootmsg(irc, "About to identify, use /OPER to enter the password"); irc->status |= OPER_HACK_IDENTIFY; return; } status = auth_check_pass(irc, irc->user->nick, password); if (load && (status == STORAGE_OK)) { status = storage_load(irc, password); } switch (status) { case STORAGE_INVALID_PASSWORD: irc_rootmsg(irc, "Incorrect password"); break; case STORAGE_NO_SUCH_USER: irc_rootmsg(irc, "The nick is (probably) not registered"); break; case STORAGE_OK: irc_rootmsg(irc, "Password accepted%s", load ? ", settings and accounts loaded" : ""); irc->status |= USTATUS_IDENTIFIED; irc_umode_set(irc, "+R", 1); if (irc->caps & CAP_SASL) { irc_user_t *iu = irc->user; irc_send_num(irc, 900, "%s!%s@%s %s :You are now logged in as %s", iu->nick, iu->user, iu->host, iu->nick, iu->nick); } bitlbee_whatsnew(irc); /* The following code is a bit hairy now. With takeover support, we shouldn't immediately auto_connect in case we're going to offer taking over an existing session. Do it in 200ms since that should give the parent process enough time to come back to us. */ if (load) { irc_channel_auto_joins(irc, NULL); if (!set_getbool(&irc->default_channel->set, "auto_join")) { irc_channel_del_user(irc->default_channel, irc->user, IRC_CDU_PART, "auto_join disabled " "for this channel."); } if (set_getbool(&irc->b->set, "auto_connect")) { irc->login_source_id = b_timeout_add(200, cmd_identify_finish, irc); } } /* If ipc_child_identify() returns FALSE, it means we're already sure that there's no takeover target (only possible in 1-process daemon mode). Start auto_connect immediately. */ if (!ipc_child_identify(irc) && load) { cmd_identify_finish(irc, 0, 0); } break; case STORAGE_OTHER_ERROR: default: irc_rootmsg(irc, "Unknown error while loading configuration"); break; } }
static void irc_cmd_join( irc_t *irc, char **cmd ) { char *comma, *s = cmd[1]; while( s ) { irc_channel_t *ic; if( ( comma = strchr( s, ',' ) ) ) *comma = '\0'; if( ( ic = irc_channel_by_name( irc, s ) ) == NULL && ( ic = irc_channel_new( irc, s ) ) ) { if( strcmp( set_getstr( &ic->set, "type" ), "control" ) != 0 ) { /* Autoconfiguration is for control channels only ATM. */ } else if( bee_group_by_name( ic->irc->b, ic->name + 1, FALSE ) ) { set_setstr( &ic->set, "group", ic->name + 1 ); set_setstr( &ic->set, "fill_by", "group" ); } else if( set_setstr( &ic->set, "protocol", ic->name + 1 ) ) { set_setstr( &ic->set, "fill_by", "protocol" ); } else if( set_setstr( &ic->set, "account", ic->name + 1 ) ) { set_setstr( &ic->set, "fill_by", "account" ); } else { /* The set commands above will run this already, but if we didn't hit any, we have to fill the channel with the default population. */ bee_irc_channel_update( ic->irc, ic, NULL ); } } else if( ic == NULL ) { irc_send_num( irc, 479, "%s :Invalid channel name", s ); goto next; } if( ic->flags & IRC_CHANNEL_JOINED ) /* Dude, you're already there... RFC doesn't have any reply for that though? */ goto next; if( ic->f->join && !ic->f->join( ic ) ) /* The story is: FALSE either means the handler showed an error message, or is doing some work before the join should be confirmed. (In the latter case, the caller should take care of that confirmation.) TRUE means all's good, let the user join the channel right away. */ goto next; irc_channel_add_user( ic, irc->user ); next: if( comma ) { s = comma + 1; *comma = ','; } else break; } }