Changes in / [e31e5b8:9b2a8c1]
- Files:
-
- 2 added
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
bitlbee.c
re31e5b8 r9b2a8c1 267 267 if( st == size ) 268 268 { 269 g_free( irc->sendbuffer ); 270 irc->sendbuffer = NULL; 271 irc->w_watch_source_id = 0; 269 if( irc->status & USTATUS_SHUTDOWN ) 270 { 271 irc_free( irc ); 272 } 273 else 274 { 275 g_free( irc->sendbuffer ); 276 irc->sendbuffer = NULL; 277 irc->w_watch_source_id = 0; 278 } 272 279 273 280 return FALSE; -
configure
re31e5b8 r9b2a8c1 39 39 40 40 events=glib 41 ldap=0 41 42 ssl=auto 42 43 … … 324 325 ret=0; 325 326 fi; 327 } 328 329 detect_ldap() 330 { 331 TMPFILE=$(mktemp /tmp/bitlbee-configure.XXXXXX) 332 if $CC -o $TMPFILE -shared -lldap 2>/dev/null >/dev/null; then 333 cat<<EOF>>Makefile.settings 334 EFLAGS+=-lldap 335 CFLAGS+= 336 EOF 337 ldap=1 338 rm -f $TMPFILE 339 ret=1 340 else 341 ldap=0 342 ret=0 343 fi 326 344 } 327 345 … … 439 457 STORAGES="xml" 440 458 459 if [ "$ldap" = "auto" ]; then 460 detect_ldap 461 fi 462 463 if [ "$ldap" = 0 ]; then 464 echo "#undef WITH_LDAP" >> config.h 465 elif [ "$ldap" = 1 ]; then 466 echo 467 echo 'LDAP support is a work in progress and does NOT work AT ALL right now.' 468 echo 469 exit 1 470 471 echo "#define WITH_LDAP 1" >> config.h 472 STORAGES="$STORAGES ldap" 473 fi 474 441 475 for i in $STORAGES; do 442 476 STORAGE_OBJS="$STORAGE_OBJS storage_$i.o" -
lib/xmltree.c
re31e5b8 r9b2a8c1 282 282 } 283 283 284 static void xt_to_string_real( struct xt_node *node, GString *str , int indent)284 static void xt_to_string_real( struct xt_node *node, GString *str ) 285 285 { 286 286 char *buf; … … 288 288 int i; 289 289 290 if( indent > 1 )291 g_string_append_len( str, "\n\t\t\t\t\t\t\t\t",292 indent < 8 ? indent : 8 );293 294 290 g_string_append_printf( str, "<%s", node->name ); 295 291 … … 316 312 317 313 for( c = node->children; c; c = c->next ) 318 xt_to_string_real( c, str, indent ? indent + 1 : 0 ); 319 320 if( indent > 0 && node->children ) 321 g_string_append_len( str, "\n\t\t\t\t\t\t\t\t", 322 indent < 8 ? indent : 8 ); 314 xt_to_string_real( c, str ); 323 315 324 316 g_string_append_printf( str, "</%s>", node->name ); … … 328 320 { 329 321 GString *ret; 322 char *real; 330 323 331 324 ret = g_string_new( "" ); 332 xt_to_string_real( node, ret, 0 ); 333 return g_string_free( ret, FALSE ); 334 } 335 336 /* WITH indentation! */ 337 char *xt_to_string_i( struct xt_node *node ) 338 { 339 GString *ret; 340 341 ret = g_string_new( "" ); 342 xt_to_string_real( node, ret, 1 ); 343 return g_string_free( ret, FALSE ); 325 xt_to_string_real( node, ret ); 326 327 real = ret->str; 328 g_string_free( ret, FALSE ); 329 330 return real; 344 331 } 345 332 346 333 void xt_print( struct xt_node *node ) 347 334 { 348 char *str = xt_to_string_i( node ); 349 fprintf( stderr, "%s", str ); 350 g_free( str ); 335 int i; 336 struct xt_node *c; 337 338 /* Indentation */ 339 for( c = node; c->parent; c = c->parent ) 340 fprintf( stderr, " " ); 341 342 /* Start the tag */ 343 fprintf( stderr, "<%s", node->name ); 344 345 /* Print the attributes */ 346 for( i = 0; node->attr[i].key; i ++ ) 347 { 348 char *v = g_markup_escape_text( node->attr[i].value, -1 ); 349 fprintf( stderr, " %s=\"%s\"", node->attr[i].key, v ); 350 g_free( v ); 351 } 352 353 /* /> in case there's really *nothing* inside this tag, otherwise 354 just >. */ 355 /* If this tag doesn't have any content at all... */ 356 if( node->text == NULL && node->children == NULL ) 357 { 358 fprintf( stderr, "/>\n" ); 359 return; 360 /* Then we're finished! */ 361 } 362 363 /* Otherwise... */ 364 fprintf( stderr, ">" ); 365 366 /* Only print the text if it contains more than whitespace (TEST). */ 367 if( node->text_len > 0 ) 368 { 369 for( i = 0; node->text[i] && isspace( node->text[i] ); i ++ ); 370 if( node->text[i] ) 371 { 372 char *v = g_markup_escape_text( node->text, -1 ); 373 fprintf( stderr, "%s", v ); 374 g_free( v ); 375 } 376 } 377 378 if( node->children ) 379 fprintf( stderr, "\n" ); 380 381 for( c = node->children; c; c = c->next ) 382 xt_print( c ); 383 384 if( node->children ) 385 for( c = node; c->parent; c = c->parent ) 386 fprintf( stderr, " " ); 387 388 /* Non-empty tag is now finished. */ 389 fprintf( stderr, "</%s>\n", node->name ); 351 390 } 352 391 -
lib/xmltree.h
re31e5b8 r9b2a8c1 84 84 struct xt_node *xt_from_string( const char *in, int text_len ); 85 85 char *xt_to_string( struct xt_node *node ); 86 char *xt_to_string_i( struct xt_node *node );87 86 void xt_print( struct xt_node *node ); 88 87 struct xt_node *xt_dup( struct xt_node *node ); -
protocols/account.c
re31e5b8 r9b2a8c1 53 53 54 54 s = set_add( &a->set, "auto_connect", "true", set_eval_account, a ); 55 s->flags |= SET_NOSAVE;55 s->flags |= ACC_SET_NOSAVE; 56 56 57 57 s = set_add( &a->set, "auto_reconnect", "true", set_eval_bool, a ); … … 61 61 62 62 s = set_add( &a->set, "nick_source", "handle", set_eval_nick_source, a ); 63 s->flags |= SET_NOSAVE; /* Just for bw compatibility! */63 s->flags |= ACC_SET_NOSAVE; /* Just for bw compatibility! */ 64 64 65 65 s = set_add( &a->set, "password", NULL, set_eval_account, a ); 66 s->flags |= SET_NOSAVE | SET_NULL_OK | SET_PASSWORD;66 s->flags |= ACC_SET_NOSAVE | SET_NULL_OK | SET_PASSWORD; 67 67 68 68 s = set_add( &a->set, "tag", NULL, set_eval_account, a ); 69 s->flags |= SET_NOSAVE;69 s->flags |= ACC_SET_NOSAVE; 70 70 71 71 s = set_add( &a->set, "username", NULL, set_eval_account, a ); 72 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY;72 s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; 73 73 set_setstr( &a->set, "username", user ); 74 74 -
protocols/account.h
re31e5b8 r9b2a8c1 61 61 typedef enum 62 62 { 63 ACC_SET_NOSAVE = 0x01, /* Don't save this setting (i.e. stored elsewhere). */ 63 64 ACC_SET_OFFLINE_ONLY = 0x02, /* Allow changes only if the acct is offline. */ 64 65 ACC_SET_ONLINE_ONLY = 0x04, /* Allow changes only if the acct is online. */ -
protocols/jabber/jabber.c
re31e5b8 r9b2a8c1 80 80 81 81 s = set_add( &acc->set, "server", NULL, set_eval_account, acc ); 82 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK;82 s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK; 83 83 84 84 s = set_add( &acc->set, "ssl", "false", set_eval_bool, acc ); -
protocols/msn/msn.c
re31e5b8 r9b2a8c1 39 39 40 40 s = set_add( &acc->set, "display_name", NULL, set_eval_display_name, acc ); 41 s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY;41 s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY; 42 42 43 43 set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc ); -
protocols/oscar/oscar.c
re31e5b8 r9b2a8c1 378 378 icq ? AIM_DEFAULT_LOGIN_SERVER_ICQ 379 379 : AIM_DEFAULT_LOGIN_SERVER_AIM, set_eval_account, acc); 380 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY;380 s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; 381 381 382 382 if (icq) { -
protocols/skype/skype.c
re31e5b8 r9b2a8c1 1561 1561 s = set_add(&acc->set, "display_name", NULL, skype_set_display_name, 1562 1562 acc); 1563 s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY;1563 s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY; 1564 1564 1565 1565 s = set_add(&acc->set, "mood_text", NULL, skype_set_mood_text, acc); … … 1567 1567 1568 1568 s = set_add(&acc->set, "call", NULL, skype_set_call, acc); 1569 s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY;1569 s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY; 1570 1570 1571 1571 s = set_add(&acc->set, "balance", NULL, skype_set_balance, acc); 1572 s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY;1572 s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY; 1573 1573 1574 1574 s = set_add(&acc->set, "skypeout_offline", "true", set_eval_bool, acc); -
protocols/twitter/twitter_lib.c
re31e5b8 r9b2a8c1 39 39 #include <ctype.h> 40 40 #include <errno.h> 41 42 /* GLib < 2.12.0 doesn't have g_ascii_strtoll(), work around using system strtoll(). */ 43 /* GLib < 2.12.4 can be buggy: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=488013 */ 44 #if !GLIB_CHECK_VERSION(2,12,5) 45 #include <stdlib.h> 46 #include <limits.h> 47 #define g_ascii_strtoll strtoll 48 #endif 41 49 42 50 #define TXL_STATUS 1 -
root_commands.c
re31e5b8 r9b2a8c1 281 281 { 282 282 if( ( irc->status & USTATUS_IDENTIFIED ) == 0 ) 283 irc_rootmsg( irc, "Please create an account first (see \x02help register\x02)" );283 irc_rootmsg( irc, "Please create an account first" ); 284 284 else if( storage_save( irc, NULL, TRUE ) == STORAGE_OK ) 285 285 irc_rootmsg( irc, "Configuration saved" ); -
set.h
re31e5b8 r9b2a8c1 45 45 typedef enum 46 46 { 47 SET_NOSAVE = 0x0001, /* Don't save this setting (i.e. stored elsewhere). */48 SET_NULL_OK = 0x0100, /* set->value == NULL is allowed. */49 SET_HIDDEN = 0x0200, /* Don't show up in setting lists. Mostly for internal storage. */50 SET_PASSWORD = 0x0400, /* Value shows up in settings list as "********". */51 SET_HIDDEN_DEFAULT = 0x0800, /* Hide unless changed from default. */47 SET_NOSAVE = 0x0001, 48 SET_NULL_OK = 0x0100, 49 SET_HIDDEN = 0x0200, 50 SET_PASSWORD = 0x0400, 51 SET_HIDDEN_DEFAULT = 0x0800, 52 52 } set_flags_t; 53 53 -
storage.c
re31e5b8 r9b2a8c1 195 195 return ret; 196 196 } 197 198 #if 0 199 Not using this yet. Test thoroughly before adding UI hooks to this function. 200 201 storage_status_t storage_rename (const char *onick, const char *nnick, const char *password) 202 { 203 storage_status_t status; 204 GList *gl = global.storage; 205 storage_t *primary_storage = gl->data; 206 irc_t *irc; 207 208 /* First, try to rename in the current write backend, assuming onick 209 * is stored there */ 210 status = primary_storage->rename(onick, nnick, password); 211 if (status != STORAGE_NO_SUCH_USER) 212 return status; 213 214 /* Try to load from a migration backend and save to the current backend. 215 * Explicitly remove the account from the migration backend as otherwise 216 * it'd still be usable under the old name */ 217 218 irc = g_new0(irc_t, 1); 219 status = storage_load(onick, password, irc); 220 if (status != STORAGE_OK) { 221 irc_free(irc); 222 return status; 223 } 224 225 g_free(irc->nick); 226 irc->nick = g_strdup(nnick); 227 228 status = storage_save(irc, FALSE); 229 if (status != STORAGE_OK) { 230 irc_free(irc); 231 return status; 232 } 233 irc_free(irc); 234 235 storage_remove(onick, password); 236 237 return STORAGE_OK; 238 } 239 #endif -
storage.h
re31e5b8 r9b2a8c1 59 59 storage_status_t storage_remove (const char *nick, const char *password); 60 60 61 /* storage_status_t storage_rename (const char *onick, const char *nnick, const char *password); */ 62 61 63 void register_storage_backend(storage_t *); 62 64 G_GNUC_MALLOC GList *storage_init(const char *primary, char **migrate); -
storage_xml.c
re31e5b8 r9b2a8c1 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 12Wilmer van der Gaast and others *4 * Copyright 2002-2006 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 29 29 #include "arc.h" 30 30 #include "md5.h" 31 #include "xmltree.h" 32 31 32 #if GLIB_CHECK_VERSION(2,8,0) 33 33 #include <glib/gstdio.h> 34 #else 35 /* GLib < 2.8.0 doesn't have g_access, so just use the system access(). */ 36 #include <unistd.h> 37 #define g_access access 38 #endif 34 39 35 40 typedef enum … … 42 47 43 48 /* To make it easier later when extending the format: */ 44 #define XML_FORMAT_VERSION "1"49 #define XML_FORMAT_VERSION 1 45 50 46 51 struct xml_parsedata 47 52 { 48 53 irc_t *irc; 49 char given_nick[MAX_NICK_LENGTH+1]; 54 char *current_setting; 55 account_t *current_account; 56 irc_channel_t *current_channel; 57 set_t **current_set_head; 58 char *given_nick; 50 59 char *given_pass; 60 xml_pass_st pass_st; 61 int unknown_tag; 62 }; 63 64 static char *xml_attr( const gchar **attr_names, const gchar **attr_values, const gchar *key ) 65 { 66 int i; 67 68 for( i = 0; attr_names[i]; i ++ ) 69 if( g_strcasecmp( attr_names[i], key ) == 0 ) 70 return (char*) attr_values[i]; 71 72 return NULL; 73 } 74 75 static void xml_destroy_xd( gpointer data ) 76 { 77 struct xml_parsedata *xd = data; 78 79 g_free( xd->given_nick ); 80 g_free( xd->given_pass ); 81 g_free( xd ); 82 } 83 84 static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer data, GError **error ) 85 { 86 struct xml_parsedata *xd = data; 87 irc_t *irc = xd->irc; 88 89 if( xd->unknown_tag > 0 ) 90 { 91 xd->unknown_tag ++; 92 } 93 else if( g_strcasecmp( element_name, "user" ) == 0 ) 94 { 95 char *nick = xml_attr( attr_names, attr_values, "nick" ); 96 char *pass = xml_attr( attr_names, attr_values, "password" ); 97 int st; 98 99 if( !nick || !pass ) 100 { 101 g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, 102 "Missing attributes for %s element", element_name ); 103 } 104 else if( ( st = md5_verify_password( xd->given_pass, pass ) ) == -1 ) 105 { 106 xd->pass_st = XML_PASS_WRONG; 107 g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, 108 "Error while decoding password attribute" ); 109 } 110 else if( st == 0 ) 111 { 112 if( xd->pass_st != XML_PASS_CHECK_ONLY ) 113 xd->pass_st = XML_PASS_OK; 114 } 115 else 116 { 117 xd->pass_st = XML_PASS_WRONG; 118 g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, 119 "Password mismatch" ); 120 } 121 } 122 else if( xd->pass_st < XML_PASS_OK ) 123 { 124 /* Let's not parse anything else if we only have to check 125 the password. */ 126 } 127 else if( g_strcasecmp( element_name, "account" ) == 0 ) 128 { 129 char *protocol, *handle, *server, *password = NULL, *autoconnect, *tag; 130 char *pass_b64 = NULL; 131 unsigned char *pass_cr = NULL; 132 int pass_len; 133 struct prpl *prpl = NULL; 134 135 handle = xml_attr( attr_names, attr_values, "handle" ); 136 pass_b64 = xml_attr( attr_names, attr_values, "password" ); 137 server = xml_attr( attr_names, attr_values, "server" ); 138 autoconnect = xml_attr( attr_names, attr_values, "autoconnect" ); 139 tag = xml_attr( attr_names, attr_values, "tag" ); 140 141 protocol = xml_attr( attr_names, attr_values, "protocol" ); 142 if( protocol ) 143 prpl = find_protocol( protocol ); 144 145 if( !handle || !pass_b64 || !protocol ) 146 g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, 147 "Missing attributes for %s element", element_name ); 148 else if( !prpl ) 149 g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, 150 "Unknown protocol: %s", protocol ); 151 else if( ( pass_len = base64_decode( pass_b64, (unsigned char**) &pass_cr ) ) && 152 arc_decode( pass_cr, pass_len, &password, xd->given_pass ) >= 0 ) 153 { 154 xd->current_account = account_add( irc->b, prpl, handle, password ); 155 if( server ) 156 set_setstr( &xd->current_account->set, "server", server ); 157 if( autoconnect ) 158 set_setstr( &xd->current_account->set, "auto_connect", autoconnect ); 159 if( tag ) 160 set_setstr( &xd->current_account->set, "tag", tag ); 161 } 162 else 163 { 164 /* Actually the _decode functions don't even return error codes, 165 but maybe they will later... */ 166 g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, 167 "Error while decrypting account password" ); 168 } 169 170 g_free( pass_cr ); 171 g_free( password ); 172 } 173 else if( g_strcasecmp( element_name, "setting" ) == 0 ) 174 { 175 char *setting; 176 177 if( xd->current_setting ) 178 { 179 g_free( xd->current_setting ); 180 xd->current_setting = NULL; 181 } 182 183 if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) ) 184 { 185 if( xd->current_channel != NULL ) 186 xd->current_set_head = &xd->current_channel->set; 187 else if( xd->current_account != NULL ) 188 xd->current_set_head = &xd->current_account->set; 189 else 190 xd->current_set_head = &xd->irc->b->set; 191 192 xd->current_setting = g_strdup( setting ); 193 } 194 else 195 g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, 196 "Missing attributes for %s element", element_name ); 197 } 198 else if( g_strcasecmp( element_name, "buddy" ) == 0 ) 199 { 200 char *handle, *nick; 201 202 handle = xml_attr( attr_names, attr_values, "handle" ); 203 nick = xml_attr( attr_names, attr_values, "nick" ); 204 205 if( xd->current_account && handle && nick ) 206 { 207 nick_set_raw( xd->current_account, handle, nick ); 208 } 209 else 210 { 211 g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, 212 "Missing attributes for %s element", element_name ); 213 } 214 } 215 else if( g_strcasecmp( element_name, "channel" ) == 0 ) 216 { 217 char *name, *type; 218 219 name = xml_attr( attr_names, attr_values, "name" ); 220 type = xml_attr( attr_names, attr_values, "type" ); 221 222 if( !name || !type ) 223 { 224 g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, 225 "Missing attributes for %s element", element_name ); 226 return; 227 } 228 229 /* The channel may exist already, for example if it's &bitlbee. 230 Also, it's possible that the user just reconnected and the 231 IRC client already rejoined all channels it was in. They 232 should still get the right settings. */ 233 if( ( xd->current_channel = irc_channel_by_name( irc, name ) ) || 234 ( xd->current_channel = irc_channel_new( irc, name ) ) ) 235 set_setstr( &xd->current_channel->set, "type", type ); 236 } 237 /* Backward compatibility: Keep this around for a while for people 238 switching from BitlBee 1.2.4+. */ 239 else if( g_strcasecmp( element_name, "chat" ) == 0 ) 240 { 241 char *handle, *channel; 242 243 handle = xml_attr( attr_names, attr_values, "handle" ); 244 channel = xml_attr( attr_names, attr_values, "channel" ); 245 246 if( xd->current_account && handle && channel ) 247 { 248 irc_channel_t *ic; 249 250 if( ( ic = irc_channel_new( irc, channel ) ) && 251 set_setstr( &ic->set, "type", "chat" ) && 252 set_setstr( &ic->set, "chat_type", "room" ) && 253 set_setstr( &ic->set, "account", xd->current_account->tag ) && 254 set_setstr( &ic->set, "room", handle ) ) 255 { 256 /* Try to pick up some settings where possible. */ 257 xd->current_channel = ic; 258 } 259 else if( ic ) 260 irc_channel_free( ic ); 261 } 262 else 263 { 264 g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, 265 "Missing attributes for %s element", element_name ); 266 } 267 } 268 else 269 { 270 xd->unknown_tag ++; 271 irc_rootmsg( irc, "Warning: Unknown XML tag found in configuration file (%s). " 272 "This may happen when downgrading BitlBee versions. " 273 "This tag will be skipped and the information will be lost " 274 "once you save your settings.", element_name ); 275 /* 276 g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, 277 "Unkown element: %s", element_name ); 278 */ 279 } 280 } 281 282 static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name, gpointer data, GError **error ) 283 { 284 struct xml_parsedata *xd = data; 285 286 if( xd->unknown_tag > 0 ) 287 { 288 xd->unknown_tag --; 289 } 290 else if( g_strcasecmp( element_name, "setting" ) == 0 && xd->current_setting ) 291 { 292 g_free( xd->current_setting ); 293 xd->current_setting = NULL; 294 } 295 else if( g_strcasecmp( element_name, "account" ) == 0 ) 296 { 297 xd->current_account = NULL; 298 } 299 else if( g_strcasecmp( element_name, "channel" ) == 0 || 300 g_strcasecmp( element_name, "chat" ) == 0 ) 301 { 302 xd->current_channel = NULL; 303 } 304 } 305 306 static void xml_text( GMarkupParseContext *ctx, const gchar *text_orig, gsize text_len, gpointer data, GError **error ) 307 { 308 char text[text_len+1]; 309 struct xml_parsedata *xd = data; 310 311 strncpy( text, text_orig, text_len ); 312 text[text_len] = 0; 313 314 if( xd->pass_st < XML_PASS_OK ) 315 { 316 /* Let's not parse anything else if we only have to check 317 the password, or if we didn't get the chance to check it 318 yet. */ 319 } 320 else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && xd->current_setting ) 321 { 322 if( xd->current_account ) 323 { 324 set_t *s = set_find( xd->current_set_head, xd->current_setting ); 325 if( s && ( s->flags & ACC_SET_ONLINE_ONLY ) ) 326 { 327 g_free( xd->current_setting ); 328 xd->current_setting = NULL; 329 return; 330 } 331 } 332 set_setstr( xd->current_set_head, xd->current_setting, (char*) text ); 333 g_free( xd->current_setting ); 334 xd->current_setting = NULL; 335 } 336 } 337 338 GMarkupParser xml_parser = 339 { 340 xml_start_element, 341 xml_end_element, 342 xml_text, 343 NULL, 344 NULL 51 345 }; 52 346 … … 60 354 } 61 355 62 static void handle_settings( struct xt_node *node, set_t **head ) 63 { 64 struct xt_node *c; 65 66 for( c = node->children; ( c = xt_find_node( c, "setting" ) ); c = c->next ) 67 { 68 char *name = xt_find_attr( c, "name" ); 69 70 if( !name ) 71 continue; 72 73 if( strcmp( node->name, "account" ) == 0 ) 74 { 75 set_t *s = set_find( head, name ); 76 if( s && ( s->flags & ACC_SET_ONLINE_ONLY ) ) 77 continue; /* U can't touch this! */ 78 } 79 set_setstr( head, name, c->text ); 80 } 81 } 82 83 static xt_status handle_account( struct xt_node *node, gpointer data ) 84 { 85 struct xml_parsedata *xd = data; 86 char *protocol, *handle, *server, *password = NULL, *autoconnect, *tag; 87 char *pass_b64 = NULL; 88 unsigned char *pass_cr = NULL; 89 int pass_len; 90 struct prpl *prpl = NULL; 356 static storage_status_t xml_load_real( irc_t *irc, const char *my_nick, const char *password, xml_pass_st action ) 357 { 358 GMarkupParseContext *ctx; 359 struct xml_parsedata *xd; 360 char *fn, buf[512]; 361 GError *gerr = NULL; 362 int fd, st; 363 364 xd = g_new0( struct xml_parsedata, 1 ); 365 xd->irc = irc; 366 xd->given_nick = g_strdup( my_nick ); 367 xd->given_pass = g_strdup( password ); 368 xd->pass_st = action; 369 nick_lc( xd->given_nick ); 370 371 fn = g_strdup_printf( "%s%s%s", global.conf->configdir, xd->given_nick, ".xml" ); 372 if( ( fd = open( fn, O_RDONLY ) ) < 0 ) 373 { 374 xml_destroy_xd( xd ); 375 g_free( fn ); 376 return STORAGE_NO_SUCH_USER; 377 } 378 g_free( fn ); 379 380 ctx = g_markup_parse_context_new( &xml_parser, 0, xd, xml_destroy_xd ); 381 382 while( ( st = read( fd, buf, sizeof( buf ) ) ) > 0 ) 383 { 384 if( !g_markup_parse_context_parse( ctx, buf, st, &gerr ) || gerr ) 385 { 386 xml_pass_st pass_st = xd->pass_st; 387 388 g_markup_parse_context_free( ctx ); 389 close( fd ); 390 391 if( pass_st == XML_PASS_WRONG ) 392 { 393 g_clear_error( &gerr ); 394 return STORAGE_INVALID_PASSWORD; 395 } 396 else 397 { 398 if( gerr && irc ) 399 irc_rootmsg( irc, "Error from XML-parser: %s", gerr->message ); 400 401 g_clear_error( &gerr ); 402 return STORAGE_OTHER_ERROR; 403 } 404 } 405 } 406 /* Just to be sure... */ 407 g_clear_error( &gerr ); 408 409 g_markup_parse_context_free( ctx ); 410 close( fd ); 411 412 if( action == XML_PASS_CHECK_ONLY ) 413 return STORAGE_OK; 414 415 return STORAGE_OK; 416 } 417 418 static storage_status_t xml_load( irc_t *irc, const char *password ) 419 { 420 return xml_load_real( irc, irc->user->nick, password, XML_PASS_UNKNOWN ); 421 } 422 423 static storage_status_t xml_check_pass( const char *my_nick, const char *password ) 424 { 425 /* This is a little bit risky because we have to pass NULL for the 426 irc_t argument. This *should* be fine, if I didn't miss anything... */ 427 return xml_load_real( NULL, my_nick, password, XML_PASS_CHECK_ONLY ); 428 } 429 430 static int xml_printf( int fd, int indent, char *fmt, ... ) 431 { 432 va_list params; 433 char *out; 434 char tabs[9] = "\t\t\t\t\t\t\t\t"; 435 int len; 436 437 /* Maybe not very clean, but who needs more than 8 levels of indentation anyway? */ 438 if( write( fd, tabs, indent <= 8 ? indent : 8 ) != indent ) 439 return 0; 440 441 va_start( params, fmt ); 442 out = g_markup_vprintf_escaped( fmt, params ); 443 va_end( params ); 444 445 len = strlen( out ); 446 len -= write( fd, out, len ); 447 g_free( out ); 448 449 return len == 0; 450 } 451 452 static gboolean xml_save_nick( gpointer key, gpointer value, gpointer data ); 453 454 static storage_status_t xml_save( irc_t *irc, int overwrite ) 455 { 456 char path[512], *path2, *pass_buf = NULL; 457 set_t *set; 91 458 account_t *acc; 92 struct xt_node *c; 93 94 handle = xt_find_attr( node, "handle" ); 95 pass_b64 = xt_find_attr( node, "password" ); 96 server = xt_find_attr( node, "server" ); 97 autoconnect = xt_find_attr( node, "autoconnect" ); 98 tag = xt_find_attr( node, "tag" ); 99 100 protocol = xt_find_attr( node, "protocol" ); 101 if( protocol ) 102 prpl = find_protocol( protocol ); 103 104 if( !handle || !pass_b64 || !protocol || !prpl ) 105 return XT_ABORT; 106 else if( ( pass_len = base64_decode( pass_b64, (unsigned char**) &pass_cr ) ) && 107 arc_decode( pass_cr, pass_len, &password, xd->given_pass ) >= 0 ) 108 { 109 acc = account_add( xd->irc->b, prpl, handle, password ); 110 if( server ) 111 set_setstr( &acc->set, "server", server ); 112 if( autoconnect ) 113 set_setstr( &acc->set, "auto_connect", autoconnect ); 114 if( tag ) 115 set_setstr( &acc->set, "tag", tag ); 116 } 117 else 118 return XT_ABORT; 119 120 g_free( pass_cr ); 121 g_free( password ); 122 123 handle_settings( node, &acc->set ); 124 125 for( c = node->children; ( c = xt_find_node( c, "buddy" ) ); c = c->next ) 126 { 127 char *handle, *nick; 128 129 handle = xt_find_attr( c, "handle" ); 130 nick = xt_find_attr( c, "nick" ); 131 132 if( handle && nick ) 133 nick_set_raw( acc, handle, nick ); 134 else 135 return XT_ABORT; 136 } 137 return XT_HANDLED; 138 } 139 140 static xt_status handle_channel( struct xt_node *node, gpointer data ) 141 { 142 struct xml_parsedata *xd = data; 143 irc_channel_t *ic; 144 char *name, *type; 145 146 name = xt_find_attr( node, "name" ); 147 type = xt_find_attr( node, "type" ); 148 149 if( !name || !type ) 150 return XT_ABORT; 151 152 /* The channel may exist already, for example if it's &bitlbee. 153 Also, it's possible that the user just reconnected and the 154 IRC client already rejoined all channels it was in. They 155 should still get the right settings. */ 156 if( ( ic = irc_channel_by_name( xd->irc, name ) ) || 157 ( ic = irc_channel_new( xd->irc, name ) ) ) 158 set_setstr( &ic->set, "type", type ); 159 160 handle_settings( node, &ic->set ); 161 162 return XT_HANDLED; 163 } 164 165 static const struct xt_handler_entry handlers[] = { 166 { "account", "user", handle_account, }, 167 { "channel", "user", handle_channel, }, 168 { NULL, NULL, NULL, }, 169 }; 170 171 static storage_status_t xml_load_real( irc_t *irc, const char *my_nick, const char *password, xml_pass_st action ) 172 { 173 struct xml_parsedata xd[1]; 174 char *fn, buf[2048]; 175 int fd, st; 176 struct xt_parser *xp; 177 struct xt_node *node; 178 storage_status_t ret = STORAGE_OTHER_ERROR; 179 180 xd->irc = irc; 181 strncpy( xd->given_nick, my_nick, MAX_NICK_LENGTH ); 182 xd->given_nick[MAX_NICK_LENGTH] = '\0'; 183 nick_lc( xd->given_nick ); 184 xd->given_pass = password; 185 186 fn = g_strconcat( global.conf->configdir, xd->given_nick, ".xml", NULL ); 187 if( ( fd = open( fn, O_RDONLY ) ) < 0 ) 188 { 189 ret = STORAGE_NO_SUCH_USER; 190 goto error; 191 } 192 193 xp = xt_new( handlers, xd ); 194 while( ( st = read( fd, buf, sizeof( buf ) ) ) > 0 ) 195 { 196 st = xt_feed( xp, buf, st ); 197 if( st != 1 ) 198 break; 199 } 200 close( fd ); 201 if( st != 0 ) 202 goto error; 203 204 node = xp->root; 205 if( node == NULL || node->next != NULL || strcmp( node->name, "user" ) != 0 ) 206 goto error; 207 208 { 209 char *nick = xt_find_attr( node, "nick" ); 210 char *pass = xt_find_attr( node, "password" ); 211 212 if( !nick || !pass ) 213 { 214 goto error; 215 } 216 else if( ( st = md5_verify_password( xd->given_pass, pass ) ) != 0 ) 217 { 218 ret = STORAGE_INVALID_PASSWORD; 219 goto error; 220 } 221 } 222 223 if( action == XML_PASS_CHECK_ONLY ) 224 { 225 ret = STORAGE_OK; 226 goto error; 227 } 228 229 /* DO NOT call xt_handle() before verifying the password! */ 230 if( xt_handle( xp, NULL, 1 ) == XT_HANDLED ) 231 ret = STORAGE_OK; 232 233 handle_settings( node, &xd->irc->b->set ); 234 235 error: 236 xt_free( xp ); 237 g_free( fn ); 238 return ret; 239 } 240 241 static storage_status_t xml_load( irc_t *irc, const char *password ) 242 { 243 return xml_load_real( irc, irc->user->nick, password, XML_PASS_UNKNOWN ); 244 } 245 246 static storage_status_t xml_check_pass( const char *my_nick, const char *password ) 247 { 248 return xml_load_real( NULL, my_nick, password, XML_PASS_CHECK_ONLY ); 249 } 250 251 252 static gboolean xml_generate_nick( gpointer key, gpointer value, gpointer data ); 253 static void xml_generate_settings( struct xt_node *cur, set_t **head ); 254 255 struct xt_node *xml_generate( irc_t *irc ) 256 { 257 char *pass_buf = NULL; 258 account_t *acc; 459 int fd; 259 460 md5_byte_t pass_md5[21]; 260 461 md5_state_t md5_state; 261 462 GSList *l; 262 struct xt_node *root, *cur; 463 464 path2 = g_strdup( irc->user->nick ); 465 nick_lc( path2 ); 466 g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, path2, ".xml" ); 467 g_free( path2 ); 468 469 if( !overwrite && g_access( path, F_OK ) == 0 ) 470 return STORAGE_ALREADY_EXISTS; 471 472 strcat( path, ".XXXXXX" ); 473 if( ( fd = mkstemp( path ) ) < 0 ) 474 { 475 irc_rootmsg( irc, "Error while opening configuration file." ); 476 return STORAGE_OTHER_ERROR; 477 } 263 478 264 479 /* Generate a salted md5sum of the password. Use 5 bytes for the salt … … 273 488 pass_buf = base64_encode( pass_md5, 21 ); 274 489 275 root = cur = xt_new_node( "user", NULL, NULL ); 276 xt_add_attr( cur, "nick", irc->user->nick ); 277 xt_add_attr( cur, "password", pass_buf ); 278 xt_add_attr( cur, "version", XML_FORMAT_VERSION ); 490 if( !xml_printf( fd, 0, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->user->nick, pass_buf, XML_FORMAT_VERSION ) ) 491 goto write_error; 279 492 280 493 g_free( pass_buf ); 281 494 282 xml_generate_settings( cur, &irc->b->set ); 495 for( set = irc->b->set; set; set = set->next ) 496 if( set->value && !( set->flags & SET_NOSAVE ) ) 497 if( !xml_printf( fd, 1, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) ) 498 goto write_error; 283 499 284 500 for( acc = irc->b->accounts; acc; acc = acc->next ) … … 292 508 g_free( pass_cr ); 293 509 294 cur = xt_new_node( "account", NULL, NULL ); 295 xt_add_attr( cur, "protocol", acc->prpl->name ); 296 xt_add_attr( cur, "handle", acc->user ); 297 xt_add_attr( cur, "password", pass_b64 ); 298 xt_add_attr( cur, "autoconnect", acc->auto_connect ? "true" : "false" ); 299 xt_add_attr( cur, "tag", acc->tag ); 300 if( acc->server && acc->server[0] ) 301 xt_add_attr( cur, "server", acc->server ); 302 510 if( !xml_printf( fd, 1, "<account protocol=\"%s\" handle=\"%s\" password=\"%s\" " 511 "autoconnect=\"%d\" tag=\"%s\"", acc->prpl->name, acc->user, 512 pass_b64, acc->auto_connect, acc->tag ) ) 513 { 514 g_free( pass_b64 ); 515 goto write_error; 516 } 303 517 g_free( pass_b64 ); 518 519 if( acc->server && acc->server[0] && !xml_printf( fd, 0, " server=\"%s\"", acc->server ) ) 520 goto write_error; 521 if( !xml_printf( fd, 0, ">\n" ) ) 522 goto write_error; 523 524 for( set = acc->set; set; set = set->next ) 525 if( set->value && !( set->flags & ACC_SET_NOSAVE ) ) 526 if( !xml_printf( fd, 2, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) ) 527 goto write_error; 304 528 305 529 /* This probably looks pretty strange. g_hash_table_foreach 306 530 is quite a PITA already (but it can't get much better in 307 C without using #define, I'm afraid), and it531 C without using #define, I'm afraid), and since it 308 532 doesn't seem to be possible to abort the foreach on write 309 533 errors, so instead let's use the _find function and 310 534 return TRUE on write errors. Which means, if we found 311 535 something, there was an error. :-) */ 312 g_hash_table_find( acc->nicks, xml_generate_nick, cur );313 314 xml_generate_settings( cur, &acc->set );315 316 xt_add_child( root, cur );536 if( g_hash_table_find( acc->nicks, xml_save_nick, & fd ) ) 537 goto write_error; 538 539 if( !xml_printf( fd, 1, "</account>\n" ) ) 540 goto write_error; 317 541 } 318 542 … … 324 548 continue; 325 549 326 cur = xt_new_node( "channel", NULL, NULL ); 327 xt_add_attr( cur, "name", ic->name ); 328 xt_add_attr( cur, "type", set_getstr( &ic->set, "type" ) ); 329 330 xml_generate_settings( cur, &ic->set ); 331 332 xt_add_child( root, cur ); 333 } 334 335 return root; 336 } 337 338 static gboolean xml_generate_nick( gpointer key, gpointer value, gpointer data ) 339 { 340 struct xt_node *node = xt_new_node( "buddy", NULL, NULL ); 341 xt_add_attr( node, "handle", key ); 342 xt_add_attr( node, "nick", value ); 343 xt_add_child( (struct xt_node *) data, node ); 344 345 return FALSE; 346 } 347 348 static void xml_generate_settings( struct xt_node *cur, set_t **head ) 349 { 350 set_t *set; 351 352 for( set = *head; set; set = set->next ) 353 if( set->value && !( set->flags & SET_NOSAVE ) ) 354 { 355 struct xt_node *xset; 356 xt_add_child( cur, xset = xt_new_node( "setting", set->value, NULL ) ); 357 xt_add_attr( xset, "name", set->key ); 358 } 359 } 360 361 static storage_status_t xml_save( irc_t *irc, int overwrite ) 362 { 363 storage_status_t ret = STORAGE_OK; 364 char path[512], *path2 = NULL, *xml = NULL; 365 struct xt_node *tree = NULL; 366 size_t len; 367 int fd; 368 369 path2 = g_strdup( irc->user->nick ); 370 nick_lc( path2 ); 371 g_snprintf( path, sizeof( path ) - 20, "%s%s%s", global.conf->configdir, path2, ".xml" ); 372 g_free( path2 ); 373 374 if( !overwrite && g_access( path, F_OK ) == 0 ) 375 return STORAGE_ALREADY_EXISTS; 376 377 strcat( path, ".XXXXXX" ); 378 if( ( fd = mkstemp( path ) ) < 0 ) 379 { 380 irc_rootmsg( irc, "Error while opening configuration file." ); 381 return STORAGE_OTHER_ERROR; 382 } 383 384 tree = xml_generate( irc ); 385 xml = xt_to_string_i( tree ); 386 len = strlen( xml ); 387 if( write( fd, xml, len ) != len || 388 fsync( fd ) != 0 || /* #559 */ 389 close( fd ) != 0 ) 390 goto error; 550 if( !xml_printf( fd, 1, "<channel name=\"%s\" type=\"%s\">\n", 551 ic->name, set_getstr( &ic->set, "type" ) ) ) 552 goto write_error; 553 554 for( set = ic->set; set; set = set->next ) 555 if( set->value && strcmp( set->key, "type" ) != 0 ) 556 if( !xml_printf( fd, 2, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) ) 557 goto write_error; 558 559 if( !xml_printf( fd, 1, "</channel>\n" ) ) 560 goto write_error; 561 } 562 563 if( !xml_printf( fd, 0, "</user>\n" ) ) 564 goto write_error; 565 566 fsync( fd ); 567 close( fd ); 391 568 392 569 path2 = g_strndup( path, strlen( path ) - 7 ); 393 570 if( rename( path, path2 ) != 0 ) 394 571 { 572 irc_rootmsg( irc, "Error while renaming temporary configuration file." ); 573 395 574 g_free( path2 ); 396 goto error; 397 } 575 unlink( path ); 576 577 return STORAGE_OTHER_ERROR; 578 } 579 398 580 g_free( path2 ); 399 581 400 goto finish; 401 402 error: 582 return STORAGE_OK; 583 584 write_error: 585 g_free( pass_buf ); 586 403 587 irc_rootmsg( irc, "Write error. Disk full?" ); 404 ret = STORAGE_OTHER_ERROR;405 406 finish:407 588 close( fd ); 408 unlink( path ); 409 g_free( xml ); 410 xt_free_node( tree ); 411 412 return ret; 413 } 414 589 590 return STORAGE_OTHER_ERROR; 591 } 592 593 static gboolean xml_save_nick( gpointer key, gpointer value, gpointer data ) 594 { 595 return !xml_printf( *( (int*) data ), 2, "<buddy handle=\"%s\" nick=\"%s\" />\n", key, value ); 596 } 415 597 416 598 static storage_status_t xml_remove( const char *nick, const char *password )
Note: See TracChangeset
for help on using the changeset viewer.