account_t *account_add( bee_t *bee, struct prpl *prpl, char *user, char *pass ) { account_t *a; set_t *s; char tag[strlen(prpl->name)+10]; if( bee->accounts ) { for( a = bee->accounts; a->next; a = a->next ); a = a->next = g_new0( account_t, 1 ); } else { bee->accounts = a = g_new0 ( account_t, 1 ); } a->prpl = prpl; a->user = g_strdup( user ); a->pass = g_strdup( pass ); a->auto_connect = 1; a->bee = bee; s = set_add( &a->set, "auto_connect", "true", set_eval_account, a ); s->flags |= SET_NOSAVE; s = set_add( &a->set, "auto_reconnect", "true", set_eval_bool, a ); s = set_add( &a->set, "nick_format", NULL, NULL, a ); s->flags |= SET_NULL_OK; s = set_add( &a->set, "nick_source", "handle", set_eval_nick_source, a ); s->flags |= SET_NOSAVE; /* Just for bw compatibility! */ s = set_add( &a->set, "password", NULL, set_eval_account, a ); s->flags |= SET_NOSAVE | SET_NULL_OK | SET_PASSWORD; s = set_add( &a->set, "tag", NULL, set_eval_account, a ); s->flags |= SET_NOSAVE; s = set_add( &a->set, "username", NULL, set_eval_account, a ); s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY; set_setstr( &a->set, "username", user ); /* Hardcode some more clever tag guesses. */ strcpy( tag, prpl->name ); if( strcmp( prpl->name, "oscar" ) == 0 ) { if( isdigit( a->user[0] ) ) strcpy( tag, "icq" ); else strcpy( tag, "aim" ); } else if( strcmp( prpl->name, "jabber" ) == 0 ) { if( strstr( a->user, "@gmail.com" ) || strstr( a->user, "@googlemail.com" ) ) strcpy( tag, "gtalk" ); else if( strstr( a->user, "@chat.facebook.com" ) ) strcpy( tag, "fb" ); } if( account_by_tag( bee, tag ) ) { char *numpos = tag + strlen( tag ); int i; for( i = 2; i < 10000; i ++ ) { sprintf( numpos, "%d", i ); if( !account_by_tag( bee, tag ) ) break; } } set_setstr( &a->set, "tag", tag ); a->nicks = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free ); /* This function adds some more settings (and might want to do more things that have to be done now, although I can't think of anything. */ if( prpl->init ) prpl->init( a ); s = set_add( &a->set, "away", NULL, set_eval_account, a ); s->flags |= SET_NULL_OK; if( a->flags & ACC_FLAG_STATUS_MESSAGE ) { s = set_add( &a->set, "status", NULL, set_eval_account, a ); s->flags |= SET_NULL_OK; } return a; }
char *set_eval_account( set_t *set, char *value ) { account_t *acc = set->data; /* Double-check: We refuse to edit on-line accounts. */ if( set->flags & ACC_SET_OFFLINE_ONLY && acc->ic ) return SET_INVALID; if( strcmp( set->key, "server" ) == 0 ) { g_free( acc->server ); if( value && *value ) { acc->server = g_strdup( value ); return value; } else { acc->server = g_strdup( set->def ); return g_strdup( set->def ); } } else if( strcmp( set->key, "username" ) == 0 ) { g_free( acc->user ); acc->user = g_strdup( value ); return value; } else if( strcmp( set->key, "password" ) == 0 ) { /* set -del should be allowed now, but I don't want to have any NULL pointers to have to deal with. */ if( !value ) value = ""; g_free( acc->pass ); acc->pass = g_strdup( value ); return NULL; /* password shouldn't be visible in plaintext! */ } else if( strcmp( set->key, "tag" ) == 0 ) { account_t *oa; /* Enforce uniqueness. */ if( ( oa = account_by_tag( acc->bee, value ) ) && oa != acc ) return SET_INVALID; g_free( acc->tag ); acc->tag = g_strdup( value ); return value; } else if( strcmp( set->key, "auto_connect" ) == 0 ) { if( !is_bool( value ) ) return SET_INVALID; acc->auto_connect = bool2int( value ); return value; } else if( strcmp( set->key, "away" ) == 0 || strcmp( set->key, "status" ) == 0 ) { if( acc->ic && acc->ic->flags & OPT_LOGGED_IN ) { /* If we're currently on-line, set the var now already (bit of a hack) and send an update. */ g_free( set->value ); set->value = g_strdup( value ); imc_away_send_update( acc->ic ); } return value; } return SET_INVALID; }
account_t *account_get( bee_t *bee, const char *id ) { account_t *a, *ret = NULL; char *handle, *s; int nr; /* Tags get priority above anything else. */ if( ( a = account_by_tag( bee, id ) ) ) return a; /* This checks if the id string ends with (...) */ if( ( handle = strchr( id, '(' ) ) && ( s = strchr( handle, ')' ) ) && s[1] == 0 ) { struct prpl *proto; *s = *handle = 0; handle ++; if( ( proto = find_protocol( id ) ) ) { for( a = bee->accounts; a; a = a->next ) if( a->prpl == proto && a->prpl->handle_cmp( handle, a->user ) == 0 ) ret = a; } /* Restore the string. */ handle --; *handle = '('; *s = ')'; if( ret ) return ret; } if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 ) { for( a = bee->accounts; a; a = a->next ) if( ( nr-- ) == 0 ) return( a ); return( NULL ); } for( a = bee->accounts; a; a = a->next ) { if( g_strcasecmp( id, a->prpl->name ) == 0 ) { if( !ret ) ret = a; else return( NULL ); /* We don't want to match more than one... */ } else if( strstr( a->user, id ) ) { if( !ret ) ret = a; else return( NULL ); } } return( ret ); }
char *set_eval_account(set_t *set, char *value) { account_t *acc = set->data; /* Double-check: We refuse to edit on-line accounts. */ if (set->flags & ACC_SET_OFFLINE_ONLY && acc->ic) { return SET_INVALID; } if (strcmp(set->key, "server") == 0) { g_free(acc->server); if (value && *value) { acc->server = g_strdup(value); return value; } else { acc->server = g_strdup(set->def); return g_strdup(set->def); } } else if (strcmp(set->key, "username") == 0) { g_free(acc->user); acc->user = g_strdup(value); return value; } else if (strcmp(set->key, "password") == 0) { /* set -del allows /oper to be used to change the password or, iff oauth is enabled, reset the oauth credential magic. */ if (!value) { if (set_getbool(&(acc->set), "oauth")) { value = ""; } else { value = PASSWORD_PENDING; ((irc_t *) acc->bee->ui_data)->status |= OPER_HACK_ACCOUNT_PASSWORD; irc_rootmsg((irc_t *) acc->bee->ui_data, "You may now use /OPER to set the password"); } } g_free(acc->pass); acc->pass = g_strdup(value); return NULL; /* password shouldn't be visible in plaintext! */ } else if (strcmp(set->key, "tag") == 0) { account_t *oa; /* Enforce uniqueness. */ if ((oa = account_by_tag(acc->bee, value)) && oa != acc) { return SET_INVALID; } g_free(acc->tag); acc->tag = g_strdup(value); return value; } else if (strcmp(set->key, "auto_connect") == 0) { if (!is_bool(value)) { return SET_INVALID; } acc->auto_connect = bool2int(value); return value; } else if (strcmp(set->key, "away") == 0 || strcmp(set->key, "status") == 0) { if (acc->ic && acc->ic->flags & OPT_LOGGED_IN) { /* If we're currently on-line, set the var now already (bit of a hack) and send an update. */ g_free(set->value); set->value = g_strdup(value); imc_away_send_update(acc->ic); } return value; } return SET_INVALID; }