Changeset 5ebff60 for protocols/account.c
- Timestamp:
- 2015-02-20T22:50:54Z (9 years ago)
- Branches:
- master
- Children:
- 0b9daac, 3d45471, 7733b8c
- Parents:
- af359b4
- git-author:
- Indent <please@…> (19-02-15 05:47:20)
- git-committer:
- dequis <dx@…> (20-02-15 22:50:54)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/account.c
raf359b4 r5ebff60 1 1 /********************************************************************\ 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * … … 32 32 }; 33 33 34 static char *set_eval_nick_source( set_t *set, char *value);35 36 account_t *account_add( bee_t *bee, struct prpl *prpl, char *user, char *pass)34 static char *set_eval_nick_source(set_t *set, char *value); 35 36 account_t *account_add(bee_t *bee, struct prpl *prpl, char *user, char *pass) 37 37 { 38 38 account_t *a; 39 39 set_t *s; 40 char tag[strlen(prpl->name)+10]; 41 42 if( bee->accounts ) 43 { 44 for( a = bee->accounts; a->next; a = a->next ); 45 a = a->next = g_new0( account_t, 1 ); 46 } 47 else 48 { 49 bee->accounts = a = g_new0 ( account_t, 1 ); 50 } 51 40 char tag[strlen(prpl->name) + 10]; 41 42 if (bee->accounts) { 43 for (a = bee->accounts; a->next; a = a->next) { 44 ; 45 } 46 a = a->next = g_new0(account_t, 1); 47 } else { 48 bee->accounts = a = g_new0(account_t, 1); 49 } 50 52 51 a->prpl = prpl; 53 a->user = g_strdup( user);54 a->pass = g_strdup( pass);52 a->user = g_strdup(user); 53 a->pass = g_strdup(pass); 55 54 a->auto_connect = 1; 56 55 a->bee = bee; 57 58 s = set_add( &a->set, "auto_connect", "true", set_eval_account, a);56 57 s = set_add(&a->set, "auto_connect", "true", set_eval_account, a); 59 58 s->flags |= SET_NOSAVE; 60 61 s = set_add( &a->set, "auto_reconnect", "true", set_eval_bool, a);62 63 s = set_add( &a->set, "nick_format", NULL, NULL, a);59 60 s = set_add(&a->set, "auto_reconnect", "true", set_eval_bool, a); 61 62 s = set_add(&a->set, "nick_format", NULL, NULL, a); 64 63 s->flags |= SET_NULL_OK; 65 66 s = set_add( &a->set, "nick_source", "handle", set_eval_nick_source, a);64 65 s = set_add(&a->set, "nick_source", "handle", set_eval_nick_source, a); 67 66 s->flags |= SET_NOSAVE; /* Just for bw compatibility! */ 68 69 s = set_add( &a->set, "password", NULL, set_eval_account, a);67 68 s = set_add(&a->set, "password", NULL, set_eval_account, a); 70 69 s->flags |= SET_NOSAVE | SET_NULL_OK | SET_PASSWORD; 71 72 s = set_add( &a->set, "tag", NULL, set_eval_account, a);70 71 s = set_add(&a->set, "tag", NULL, set_eval_account, a); 73 72 s->flags |= SET_NOSAVE; 74 75 s = set_add( &a->set, "username", NULL, set_eval_account, a);73 74 s = set_add(&a->set, "username", NULL, set_eval_account, a); 76 75 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY; 77 set_setstr( &a->set, "username", user);78 76 set_setstr(&a->set, "username", user); 77 79 78 /* Hardcode some more clever tag guesses. */ 80 strcpy( tag, prpl->name ); 81 if( strcmp( prpl->name, "oscar" ) == 0 ) 82 { 83 if( g_ascii_isdigit( a->user[0] ) ) 84 strcpy( tag, "icq" ); 85 else 86 strcpy( tag, "aim" ); 87 } 88 else if( strcmp( prpl->name, "jabber" ) == 0 ) 89 { 90 if( strstr( a->user, "@gmail.com" ) || 91 strstr( a->user, "@googlemail.com" ) ) 92 strcpy( tag, "gtalk" ); 93 else if( strstr( a->user, "@chat.facebook.com" ) ) 94 strcpy( tag, "fb" ); 95 } 96 97 if( account_by_tag( bee, tag ) ) 98 { 99 char *numpos = tag + strlen( tag ); 79 strcpy(tag, prpl->name); 80 if (strcmp(prpl->name, "oscar") == 0) { 81 if (g_ascii_isdigit(a->user[0])) { 82 strcpy(tag, "icq"); 83 } else { 84 strcpy(tag, "aim"); 85 } 86 } else if (strcmp(prpl->name, "jabber") == 0) { 87 if (strstr(a->user, "@gmail.com") || 88 strstr(a->user, "@googlemail.com")) { 89 strcpy(tag, "gtalk"); 90 } else if (strstr(a->user, "@chat.facebook.com")) { 91 strcpy(tag, "fb"); 92 } 93 } 94 95 if (account_by_tag(bee, tag)) { 96 char *numpos = tag + strlen(tag); 100 97 int i; 101 98 102 for( i = 2; i < 10000; i ++ ) 103 { 104 sprintf( numpos, "%d", i ); 105 if( !account_by_tag( bee, tag ) ) 99 for (i = 2; i < 10000; i++) { 100 sprintf(numpos, "%d", i); 101 if (!account_by_tag(bee, tag)) { 106 102 break; 107 } 108 } 109 set_setstr( &a->set, "tag", tag ); 110 111 a->nicks = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free ); 112 103 } 104 } 105 } 106 set_setstr(&a->set, "tag", tag); 107 108 a->nicks = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); 109 113 110 /* This function adds some more settings (and might want to do more 114 111 things that have to be done now, although I can't think of anything. */ 115 if( prpl->init ) 116 prpl->init( a ); 117 118 s = set_add( &a->set, "away", NULL, set_eval_account, a ); 112 if (prpl->init) { 113 prpl->init(a); 114 } 115 116 s = set_add(&a->set, "away", NULL, set_eval_account, a); 119 117 s->flags |= SET_NULL_OK; 120 121 if( a->flags & ACC_FLAG_STATUS_MESSAGE ) 122 { 123 s = set_add( &a->set, "status", NULL, set_eval_account, a ); 118 119 if (a->flags & ACC_FLAG_STATUS_MESSAGE) { 120 s = set_add(&a->set, "status", NULL, set_eval_account, a); 124 121 s->flags |= SET_NULL_OK; 125 122 } 126 123 127 124 return a; 128 125 } 129 126 130 char *set_eval_account( set_t *set, char *value)127 char *set_eval_account(set_t *set, char *value) 131 128 { 132 129 account_t *acc = set->data; 133 130 134 131 /* Double-check: We refuse to edit on-line accounts. */ 135 if ( set->flags & ACC_SET_OFFLINE_ONLY && acc->ic )132 if (set->flags & ACC_SET_OFFLINE_ONLY && acc->ic) { 136 133 return SET_INVALID; 137 138 if( strcmp( set->key, "server" ) == 0 ) 139 { 140 g_free( acc->server ); 141 if( value && *value ) 142 { 143 acc->server = g_strdup( value ); 134 } 135 136 if (strcmp(set->key, "server") == 0) { 137 g_free(acc->server); 138 if (value && *value) { 139 acc->server = g_strdup(value); 144 140 return value; 145 } 146 else 147 { 148 acc->server = g_strdup( set->def ); 149 return g_strdup( set->def ); 150 } 151 } 152 else if( strcmp( set->key, "username" ) == 0 ) 153 { 154 g_free( acc->user ); 155 acc->user = g_strdup( value ); 141 } else { 142 acc->server = g_strdup(set->def); 143 return g_strdup(set->def); 144 } 145 } else if (strcmp(set->key, "username") == 0) { 146 g_free(acc->user); 147 acc->user = g_strdup(value); 156 148 return value; 157 } 158 else if( strcmp( set->key, "password" ) == 0 ) 159 { 149 } else if (strcmp(set->key, "password") == 0) { 160 150 /* set -del allows /oper to be used to change the password or, 161 151 iff oauth is enabled, reset the oauth credential magic. 162 152 */ 163 if ( !value) {164 if ( set_getbool( &(acc->set), "oauth" )) {153 if (!value) { 154 if (set_getbool(&(acc->set), "oauth")) { 165 155 value = ""; 166 156 } else { 167 157 value = PASSWORD_PENDING; 168 ((irc_t *)acc->bee->ui_data)->status |= OPER_HACK_ACCOUNT_PASSWORD; 169 irc_rootmsg((irc_t *)acc->bee->ui_data, "You may now use /OPER to set the password"); 170 } 171 } 172 173 g_free( acc->pass ); 174 acc->pass = g_strdup( value ); 175 return NULL; /* password shouldn't be visible in plaintext! */ 176 } 177 else if( strcmp( set->key, "tag" ) == 0 ) 178 { 158 ((irc_t *) acc->bee->ui_data)->status |= OPER_HACK_ACCOUNT_PASSWORD; 159 irc_rootmsg((irc_t *) acc->bee->ui_data, "You may now use /OPER to set the password"); 160 } 161 } 162 163 g_free(acc->pass); 164 acc->pass = g_strdup(value); 165 return NULL; /* password shouldn't be visible in plaintext! */ 166 } else if (strcmp(set->key, "tag") == 0) { 179 167 account_t *oa; 180 168 181 169 /* Enforce uniqueness. */ 182 if ( ( oa = account_by_tag( acc->bee, value ) ) && oa != acc )170 if ((oa = account_by_tag(acc->bee, value)) && oa != acc) { 183 171 return SET_INVALID; 184 185 g_free( acc->tag ); 186 acc->tag = g_strdup( value ); 172 } 173 174 g_free(acc->tag); 175 acc->tag = g_strdup(value); 187 176 return value; 188 } 189 else if( strcmp( set->key, "auto_connect" ) == 0 ) 190 { 191 if( !is_bool( value ) ) 177 } else if (strcmp(set->key, "auto_connect") == 0) { 178 if (!is_bool(value)) { 192 179 return SET_INVALID; 193 194 acc->auto_connect = bool2int( value ); 180 } 181 182 acc->auto_connect = bool2int(value); 195 183 return value; 196 } 197 else if( strcmp( set->key, "away" ) == 0 || 198 strcmp( set->key, "status" ) == 0 ) 199 { 200 if( acc->ic && acc->ic->flags & OPT_LOGGED_IN ) 201 { 184 } else if (strcmp(set->key, "away") == 0 || 185 strcmp(set->key, "status") == 0) { 186 if (acc->ic && acc->ic->flags & OPT_LOGGED_IN) { 202 187 /* If we're currently on-line, set the var now already 203 188 (bit of a hack) and send an update. */ 204 g_free( set->value);205 set->value = g_strdup( value);206 207 imc_away_send_update( acc->ic);208 } 209 189 g_free(set->value); 190 set->value = g_strdup(value); 191 192 imc_away_send_update(acc->ic); 193 } 194 210 195 return value; 211 196 } 212 197 213 198 return SET_INVALID; 214 199 } 215 200 216 201 /* For bw compatibility, have this write-only setting. */ 217 static char *set_eval_nick_source( set_t *set, char *value)202 static char *set_eval_nick_source(set_t *set, char *value) 218 203 { 219 204 account_t *a = set->data; 220 221 if( strcmp( value, "full_name" ) == 0 ) 222 set_setstr( &a->set, "nick_format", "%full_name" ); 223 else if( strcmp( value, "first_name" ) == 0 ) 224 set_setstr( &a->set, "nick_format", "%first_name" ); 225 else 226 set_setstr( &a->set, "nick_format", "%-@nick" ); 227 205 206 if (strcmp(value, "full_name") == 0) { 207 set_setstr(&a->set, "nick_format", "%full_name"); 208 } else if (strcmp(value, "first_name") == 0) { 209 set_setstr(&a->set, "nick_format", "%first_name"); 210 } else { 211 set_setstr(&a->set, "nick_format", "%-@nick"); 212 } 213 228 214 return value; 229 215 } 230 216 231 account_t *account_get( bee_t *bee, const char *id)217 account_t *account_get(bee_t *bee, const char *id) 232 218 { 233 219 account_t *a, *ret = NULL; 234 220 char *handle, *s; 235 221 int nr; 236 222 237 223 /* Tags get priority above anything else. */ 238 if ( ( a = account_by_tag( bee, id ) ) )224 if ((a = account_by_tag(bee, id))) { 239 225 return a; 240 226 } 227 241 228 /* This checks if the id string ends with (...) */ 242 if( ( handle = strchr( id, '(' ) ) && ( s = strchr( handle, ')' ) ) && s[1] == 0 ) 243 { 229 if ((handle = strchr(id, '(')) && (s = strchr(handle, ')')) && s[1] == 0) { 244 230 struct prpl *proto; 245 231 246 232 *s = *handle = 0; 247 handle ++; 248 249 if( ( proto = find_protocol( id ) ) ) 250 { 251 for( a = bee->accounts; a; a = a->next ) 252 if( a->prpl == proto && 253 a->prpl->handle_cmp( handle, a->user ) == 0 ) 233 handle++; 234 235 if ((proto = find_protocol(id))) { 236 for (a = bee->accounts; a; a = a->next) { 237 if (a->prpl == proto && 238 a->prpl->handle_cmp(handle, a->user) == 0) { 254 239 ret = a; 255 } 256 240 } 241 } 242 } 243 257 244 /* Restore the string. */ 258 handle 245 handle--; 259 246 *handle = '('; 260 247 *s = ')'; 261 262 if ( ret )248 249 if (ret) { 263 250 return ret; 264 }265 266 if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 ) 267 {268 for ( a = bee->accounts; a; a = a->next )269 if ( ( nr-- ) == 0 )270 return( a);271 272 return( NULL );273 } 274 275 for( a = bee->accounts; a; a = a->next )276 { 277 if( g_strcasecmp( id, a->prpl->name ) == 0 )278 {279 if ( !ret )251 } 252 } 253 254 if (sscanf(id, "%d", &nr) == 1 && nr < 1000) { 255 for (a = bee->accounts; a; a = a->next) { 256 if ((nr--) == 0) { 257 return(a); 258 } 259 } 260 261 return(NULL); 262 } 263 264 for (a = bee->accounts; a; a = a->next) { 265 if (g_strcasecmp(id, a->prpl->name) == 0) { 266 if (!ret) { 280 267 ret = a; 281 else 282 return( NULL ); /* We don't want to match more than one... */ 283 } 284 else if( strstr( a->user, id ) ) 285 { 286 if( !ret ) 268 } else { 269 return(NULL); /* We don't want to match more than one... */ 270 } 271 } else if (strstr(a->user, id)) { 272 if (!ret) { 287 273 ret = a; 288 else 289 return( NULL ); 290 } 291 } 292 293 return( ret ); 294 } 295 296 account_t *account_by_tag( bee_t *bee, const char *tag ) 274 } else { 275 return(NULL); 276 } 277 } 278 } 279 280 return(ret); 281 } 282 283 account_t *account_by_tag(bee_t *bee, const char *tag) 297 284 { 298 285 account_t *a; 299 300 for ( a = bee->accounts; a; a = a->next )301 if ( a->tag && g_strcasecmp( tag, a->tag ) == 0 )286 287 for (a = bee->accounts; a; a = a->next) { 288 if (a->tag && g_strcasecmp(tag, a->tag) == 0) { 302 289 return a; 303 290 } 291 } 292 304 293 return NULL; 305 294 } 306 295 307 void account_del( bee_t *bee, account_t *acc)296 void account_del(bee_t *bee, account_t *acc) 308 297 { 309 298 account_t *a, *l = NULL; 310 311 if ( acc->ic )299 300 if (acc->ic) { 312 301 /* Caller should have checked, accounts still in use can't be deleted. */ 313 302 return; 314 315 for( a = bee->accounts; a; a = (l=a)->next ) 316 if( a == acc )317 {318 if ( l )303 } 304 305 for (a = bee->accounts; a; a = (l = a)->next) { 306 if (a == acc) { 307 if (l) { 319 308 l->next = a->next; 320 else309 } else { 321 310 bee->accounts = a->next; 322 311 } 312 323 313 /** FIXME 324 314 for( c = bee->chatrooms; c; c = nc ) 325 315 { 326 327 328 316 nc = c->next; 317 if( acc == c->acc ) 318 chat_del( bee, c ); 329 319 } 330 320 */ 331 332 while( a->set ) 333 set_del( &a->set, a->set->key ); 334 335 g_hash_table_destroy( a->nicks ); 336 337 g_free( a->tag ); 338 g_free( a->user ); 339 g_free( a->pass ); 340 g_free( a->server ); 341 if( a->reconnect ) /* This prevents any reconnect still queued to happen */ 342 cancel_auto_reconnect( a ); 343 g_free( a ); 344 321 322 while (a->set) { 323 set_del(&a->set, a->set->key); 324 } 325 326 g_hash_table_destroy(a->nicks); 327 328 g_free(a->tag); 329 g_free(a->user); 330 g_free(a->pass); 331 g_free(a->server); 332 if (a->reconnect) { /* This prevents any reconnect still queued to happen */ 333 cancel_auto_reconnect(a); 334 } 335 g_free(a); 336 345 337 break; 346 338 } 347 }348 349 static gboolean account_on_timeout( gpointer d, gint fd, b_input_condition cond ); 350 351 void account_on( bee_t *bee, account_t *a ) 352 { 353 if( a->ic ) 354 {339 } 340 } 341 342 static gboolean account_on_timeout(gpointer d, gint fd, b_input_condition cond); 343 344 void account_on(bee_t *bee, account_t *a) 345 { 346 if (a->ic) { 355 347 /* Trying to enable an already-enabled account */ 356 348 return; 357 349 } 358 359 cancel_auto_reconnect( a);360 350 351 cancel_auto_reconnect(a); 352 361 353 a->reconnect = 0; 362 a->prpl->login( a ); 363 364 if( a->ic && !( a->ic->flags & ( OPT_SLOW_LOGIN | OPT_LOGGED_IN ) ) ) 365 a->ic->keepalive = b_timeout_add( 120000, account_on_timeout, a->ic ); 366 } 367 368 void account_off( bee_t *bee, account_t *a ) 369 { 370 imc_logout( a->ic, FALSE ); 354 a->prpl->login(a); 355 356 if (a->ic && !(a->ic->flags & (OPT_SLOW_LOGIN | OPT_LOGGED_IN))) { 357 a->ic->keepalive = b_timeout_add(120000, account_on_timeout, a->ic); 358 } 359 } 360 361 void account_off(bee_t *bee, account_t *a) 362 { 363 imc_logout(a->ic, FALSE); 371 364 a->ic = NULL; 372 if( a->reconnect ) 373 { 365 if (a->reconnect) { 374 366 /* Shouldn't happen */ 375 cancel_auto_reconnect( a);376 } 377 } 378 379 static gboolean account_on_timeout( gpointer d, gint fd, b_input_condition cond)367 cancel_auto_reconnect(a); 368 } 369 } 370 371 static gboolean account_on_timeout(gpointer d, gint fd, b_input_condition cond) 380 372 { 381 373 struct im_connection *ic = d; 382 383 if( !( ic->flags & ( OPT_SLOW_LOGIN | OPT_LOGGED_IN ) ) ) 384 { 385 imcb_error( ic, "Connection timeout" ); 386 imc_logout( ic, TRUE ); 387 } 388 374 375 if (!(ic->flags & (OPT_SLOW_LOGIN | OPT_LOGGED_IN))) { 376 imcb_error(ic, "Connection timeout"); 377 imc_logout(ic, TRUE); 378 } 379 389 380 return FALSE; 390 381 } 391 382 392 struct account_reconnect_delay 393 { 383 struct account_reconnect_delay { 394 384 int start; 395 385 char op; … … 398 388 }; 399 389 400 int account_reconnect_delay_parse( char *value, struct account_reconnect_delay *p)401 { 402 memset( p, 0, sizeof( *p ));390 int account_reconnect_delay_parse(char *value, struct account_reconnect_delay *p) 391 { 392 memset(p, 0, sizeof(*p)); 403 393 /* A whole day seems like a sane "maximum maximum". */ 404 394 p->max = 86400; 405 395 406 396 /* Format: /[0-9]+([*+][0-9]+(<[0-9+])?)?/ */ 407 while ( *value && g_ascii_isdigit( *value ) )397 while (*value && g_ascii_isdigit(*value)) { 408 398 p->start = p->start * 10 + *value++ - '0'; 409 399 } 400 410 401 /* Sure, call me evil for implementing my own fscanf here, but it's 411 402 dead simple and I immediately know where to continue parsing. */ 412 413 if ( *value == 0 )403 404 if (*value == 0) { 414 405 /* If the string ends now, the delay is constant. */ 415 406 return 1; 416 else if( *value != '+' && *value != '*' )407 } else if (*value != '+' && *value != '*') { 417 408 /* Otherwise allow either a + or a * */ 418 409 return 0; 419 410 } 411 420 412 p->op = *value++; 421 413 422 414 /* + or * the delay by this number every time. */ 423 while ( *value && g_ascii_isdigit( *value ) )415 while (*value && g_ascii_isdigit(*value)) { 424 416 p->step = p->step * 10 + *value++ - '0'; 425 426 if( *value == 0 ) 417 } 418 419 if (*value == 0) { 427 420 /* Use the default maximum (one day). */ 428 421 return 1; 429 else if( *value != '<' )422 } else if (*value != '<') { 430 423 return 0; 431 424 } 425 432 426 p->max = 0; 433 value 434 while ( *value && g_ascii_isdigit( *value ) )427 value++; 428 while (*value && g_ascii_isdigit(*value)) { 435 429 p->max = p->max * 10 + *value++ - '0'; 436 430 } 431 437 432 return p->max > 0; 438 433 } 439 434 440 char *set_eval_account_reconnect_delay( set_t *set, char *value)435 char *set_eval_account_reconnect_delay(set_t *set, char *value) 441 436 { 442 437 struct account_reconnect_delay p; 443 444 return account_reconnect_delay_parse( value, &p) ? value : SET_INVALID;445 } 446 447 int account_reconnect_delay( account_t *a)448 { 449 char *setting = set_getstr( &a->bee->set, "auto_reconnect_delay");438 439 return account_reconnect_delay_parse(value, &p) ? value : SET_INVALID; 440 } 441 442 int account_reconnect_delay(account_t *a) 443 { 444 char *setting = set_getstr(&a->bee->set, "auto_reconnect_delay"); 450 445 struct account_reconnect_delay p; 451 452 if( account_reconnect_delay_parse( setting, &p ) ) 453 { 454 if( a->auto_reconnect_delay == 0 ) 446 447 if (account_reconnect_delay_parse(setting, &p)) { 448 if (a->auto_reconnect_delay == 0) { 455 449 a->auto_reconnect_delay = p.start; 456 else if( p.op == '+' )450 } else if (p.op == '+') { 457 451 a->auto_reconnect_delay += p.step; 458 else if( p.op == '*' )452 } else if (p.op == '*') { 459 453 a->auto_reconnect_delay *= p.step; 460 461 if( a->auto_reconnect_delay > p.max ) 454 } 455 456 if (a->auto_reconnect_delay > p.max) { 462 457 a->auto_reconnect_delay = p.max; 463 } 464 else 465 { 458 } 459 } else { 466 460 a->auto_reconnect_delay = 0; 467 461 } 468 462 469 463 return a->auto_reconnect_delay; 470 464 } 471 465 472 int protocol_account_islocal( const char* protocol)466 int protocol_account_islocal(const char* protocol) 473 467 { 474 468 const char** p = account_protocols_local; 469 475 470 do { 476 if ( strcmp( *p, protocol ) == 0 )471 if (strcmp(*p, protocol) == 0) { 477 472 return 1; 478 } while( *( ++p ) ); 473 } 474 } while (*(++p)); 479 475 return 0; 480 476 }
Note: See TracChangeset
for help on using the changeset viewer.