Changes in / [9b2a8c1:e31e5b8]
- Files:
-
- 2 deleted
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
bitlbee.c
r9b2a8c1 re31e5b8 267 267 if( st == size ) 268 268 { 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 } 269 g_free( irc->sendbuffer ); 270 irc->sendbuffer = NULL; 271 irc->w_watch_source_id = 0; 279 272 280 273 return FALSE; -
configure
r9b2a8c1 re31e5b8 39 39 40 40 events=glib 41 ldap=042 41 ssl=auto 43 42 … … 325 324 ret=0; 326 325 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; then333 cat<<EOF>>Makefile.settings334 EFLAGS+=-lldap335 CFLAGS+=336 EOF337 ldap=1338 rm -f $TMPFILE339 ret=1340 else341 ldap=0342 ret=0343 fi344 326 } 345 327 … … 457 439 STORAGES="xml" 458 440 459 if [ "$ldap" = "auto" ]; then460 detect_ldap461 fi462 463 if [ "$ldap" = 0 ]; then464 echo "#undef WITH_LDAP" >> config.h465 elif [ "$ldap" = 1 ]; then466 echo467 echo 'LDAP support is a work in progress and does NOT work AT ALL right now.'468 echo469 exit 1470 471 echo "#define WITH_LDAP 1" >> config.h472 STORAGES="$STORAGES ldap"473 fi474 475 441 for i in $STORAGES; do 476 442 STORAGE_OBJS="$STORAGE_OBJS storage_$i.o" -
lib/xmltree.c
r9b2a8c1 re31e5b8 282 282 } 283 283 284 static void xt_to_string_real( struct xt_node *node, GString *str )284 static void xt_to_string_real( struct xt_node *node, GString *str, int indent ) 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 290 294 g_string_append_printf( str, "<%s", node->name ); 291 295 … … 312 316 313 317 for( c = node->children; c; c = c->next ) 314 xt_to_string_real( c, str ); 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 ); 315 323 316 324 g_string_append_printf( str, "</%s>", node->name ); … … 320 328 { 321 329 GString *ret; 322 char *real;323 330 324 331 ret = g_string_new( "" ); 325 xt_to_string_real( node, ret ); 326 327 real = ret->str; 328 g_string_free( ret, FALSE ); 329 330 return real; 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 ); 331 344 } 332 345 333 346 void xt_print( struct xt_node *node ) 334 347 { 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 ); 348 char *str = xt_to_string_i( node ); 349 fprintf( stderr, "%s", str ); 350 g_free( str ); 390 351 } 391 352 -
lib/xmltree.h
r9b2a8c1 re31e5b8 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 ); 86 87 void xt_print( struct xt_node *node ); 87 88 struct xt_node *xt_dup( struct xt_node *node ); -
protocols/account.c
r9b2a8c1 re31e5b8 53 53 54 54 s = set_add( &a->set, "auto_connect", "true", set_eval_account, a ); 55 s->flags |= ACC_SET_NOSAVE;55 s->flags |= 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 |= ACC_SET_NOSAVE; /* Just for bw compatibility! */63 s->flags |= SET_NOSAVE; /* Just for bw compatibility! */ 64 64 65 65 s = set_add( &a->set, "password", NULL, set_eval_account, a ); 66 s->flags |= ACC_SET_NOSAVE | SET_NULL_OK | SET_PASSWORD;66 s->flags |= 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 |= ACC_SET_NOSAVE;69 s->flags |= SET_NOSAVE; 70 70 71 71 s = set_add( &a->set, "username", NULL, set_eval_account, a ); 72 s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;72 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY; 73 73 set_setstr( &a->set, "username", user ); 74 74 -
protocols/account.h
r9b2a8c1 re31e5b8 61 61 typedef enum 62 62 { 63 ACC_SET_NOSAVE = 0x01, /* Don't save this setting (i.e. stored elsewhere). */64 63 ACC_SET_OFFLINE_ONLY = 0x02, /* Allow changes only if the acct is offline. */ 65 64 ACC_SET_ONLINE_ONLY = 0x04, /* Allow changes only if the acct is online. */ -
protocols/jabber/jabber.c
r9b2a8c1 re31e5b8 80 80 81 81 s = set_add( &acc->set, "server", NULL, set_eval_account, acc ); 82 s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK;82 s->flags |= 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
r9b2a8c1 re31e5b8 39 39 40 40 s = set_add( &acc->set, "display_name", NULL, set_eval_display_name, acc ); 41 s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;41 s->flags |= 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
r9b2a8c1 re31e5b8 378 378 icq ? AIM_DEFAULT_LOGIN_SERVER_ICQ 379 379 : AIM_DEFAULT_LOGIN_SERVER_AIM, set_eval_account, acc); 380 s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;380 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY; 381 381 382 382 if (icq) { -
protocols/skype/skype.c
r9b2a8c1 re31e5b8 1561 1561 s = set_add(&acc->set, "display_name", NULL, skype_set_display_name, 1562 1562 acc); 1563 s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;1563 s->flags |= 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 |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;1569 s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY; 1570 1570 1571 1571 s = set_add(&acc->set, "balance", NULL, skype_set_balance, acc); 1572 s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;1572 s->flags |= 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
r9b2a8c1 re31e5b8 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 strtoll48 #endif49 41 50 42 #define TXL_STATUS 1 -
root_commands.c
r9b2a8c1 re31e5b8 281 281 { 282 282 if( ( irc->status & USTATUS_IDENTIFIED ) == 0 ) 283 irc_rootmsg( irc, "Please create an account first " );283 irc_rootmsg( irc, "Please create an account first (see \x02help register\x02)" ); 284 284 else if( storage_save( irc, NULL, TRUE ) == STORAGE_OK ) 285 285 irc_rootmsg( irc, "Configuration saved" ); -
set.h
r9b2a8c1 re31e5b8 45 45 typedef enum 46 46 { 47 SET_NOSAVE = 0x0001, 48 SET_NULL_OK = 0x0100, 49 SET_HIDDEN = 0x0200, 50 SET_PASSWORD = 0x0400, 51 SET_HIDDEN_DEFAULT = 0x0800, 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. */ 52 52 } set_flags_t; 53 53 -
storage.c
r9b2a8c1 re31e5b8 195 195 return ret; 196 196 } 197 198 #if 0199 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 onick209 * 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 otherwise216 * 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
r9b2a8c1 re31e5b8 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 63 61 void register_storage_backend(storage_t *); 64 62 G_GNUC_MALLOC GList *storage_init(const char *primary, char **migrate); -
storage_xml.c
r9b2a8c1 re31e5b8 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 06Wilmer van der Gaast and others *4 * Copyright 2002-2012 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 29 29 #include "arc.h" 30 30 #include "md5.h" 31 32 #if GLIB_CHECK_VERSION(2,8,0) 31 #include "xmltree.h" 32 33 33 #include <glib/gstdio.h> 34 #else35 /* GLib < 2.8.0 doesn't have g_access, so just use the system access(). */36 #include <unistd.h>37 #define g_access access38 #endif39 34 40 35 typedef enum … … 47 42 48 43 /* To make it easier later when extending the format: */ 49 #define XML_FORMAT_VERSION 144 #define XML_FORMAT_VERSION "1" 50 45 51 46 struct xml_parsedata 52 47 { 53 48 irc_t *irc; 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; 49 char given_nick[MAX_NICK_LENGTH+1]; 59 50 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 else116 {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 check125 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 else163 {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 else190 xd->current_set_head = &xd->irc->b->set;191 192 xd->current_setting = g_strdup( setting );193 }194 else195 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 else210 {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 the231 IRC client already rejoined all channels it was in. They232 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 people238 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 else263 {264 g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,265 "Missing attributes for %s element", element_name );266 }267 }268 else269 {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 check317 the password, or if we didn't get the chance to check it318 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 NULL345 51 }; 346 52 … … 354 60 } 355 61 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; 91 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 356 171 static storage_status_t xml_load_real( irc_t *irc, const char *my_nick, const char *password, xml_pass_st action ) 357 172 { 358 GMarkupParseContext *ctx; 359 struct xml_parsedata *xd; 360 char *fn, buf[512]; 361 GError *gerr = NULL; 173 struct xml_parsedata xd[1]; 174 char *fn, buf[2048]; 362 175 int fd, st; 363 364 xd = g_new0( struct xml_parsedata, 1 ); 176 struct xt_parser *xp; 177 struct xt_node *node; 178 storage_status_t ret = STORAGE_OTHER_ERROR; 179 365 180 xd->irc = irc; 366 xd->given_nick = g_strdup( my_nick ); 367 xd->given_pass = g_strdup( password ); 368 xd->pass_st = action; 181 strncpy( xd->given_nick, my_nick, MAX_NICK_LENGTH ); 182 xd->given_nick[MAX_NICK_LENGTH] = '\0'; 369 183 nick_lc( xd->given_nick ); 370 371 fn = g_strdup_printf( "%s%s%s", global.conf->configdir, xd->given_nick, ".xml" ); 184 xd->given_pass = password; 185 186 fn = g_strconcat( global.conf->configdir, xd->given_nick, ".xml", NULL ); 372 187 if( ( fd = open( fn, O_RDONLY ) ) < 0 ) 373 188 { 374 xml_destroy_xd( xd ); 375 g_free( fn ); 376 return STORAGE_NO_SUCH_USER; 377 } 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 ); 378 237 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; 238 return ret; 416 239 } 417 240 … … 423 246 static storage_status_t xml_check_pass( const char *my_nick, const char *password ) 424 247 { 425 /* This is a little bit risky because we have to pass NULL for the426 irc_t argument. This *should* be fine, if I didn't miss anything... */427 248 return xml_load_real( NULL, my_nick, password, XML_PASS_CHECK_ONLY ); 428 249 } 429 250 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; 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; 458 258 account_t *acc; 459 int fd;460 259 md5_byte_t pass_md5[21]; 461 260 md5_state_t md5_state; 462 261 GSList *l; 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 } 262 struct xt_node *root, *cur; 478 263 479 264 /* Generate a salted md5sum of the password. Use 5 bytes for the salt … … 488 273 pass_buf = base64_encode( pass_md5, 21 ); 489 274 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; 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 ); 492 279 493 280 g_free( pass_buf ); 494 281 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; 282 xml_generate_settings( cur, &irc->b->set ); 499 283 500 284 for( acc = irc->b->accounts; acc; acc = acc->next ) … … 508 292 g_free( pass_cr ); 509 293 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 } 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 517 303 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;528 304 529 305 /* This probably looks pretty strange. g_hash_table_foreach 530 306 is quite a PITA already (but it can't get much better in 531 C without using #define, I'm afraid), and sinceit307 C without using #define, I'm afraid), and it 532 308 doesn't seem to be possible to abort the foreach on write 533 309 errors, so instead let's use the _find function and 534 310 return TRUE on write errors. Which means, if we found 535 311 something, there was an error. :-) */ 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;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 ); 541 317 } 542 318 … … 548 324 continue; 549 325 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 ); 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; 568 391 569 392 path2 = g_strndup( path, strlen( path ) - 7 ); 570 393 if( rename( path, path2 ) != 0 ) 571 394 { 572 irc_rootmsg( irc, "Error while renaming temporary configuration file." );573 574 395 g_free( path2 ); 575 unlink( path ); 576 577 return STORAGE_OTHER_ERROR; 578 } 579 396 goto error; 397 } 580 398 g_free( path2 ); 581 399 582 return STORAGE_OK; 583 584 write_error: 585 g_free( pass_buf ); 586 400 goto finish; 401 402 error: 587 403 irc_rootmsg( irc, "Write error. Disk full?" ); 404 ret = STORAGE_OTHER_ERROR; 405 406 finish: 588 407 close( fd ); 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 } 408 unlink( path ); 409 g_free( xml ); 410 xt_free_node( tree ); 411 412 return ret; 413 } 414 597 415 598 416 static storage_status_t xml_remove( const char *nick, const char *password )
Note: See TracChangeset
for help on using the changeset viewer.