source: storage_xml.c @ c121f89

Last change on this file since c121f89 was c121f89, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-06-14T20:30:25Z

xml_load() works pretty well now.

  • Property mode set to 100644
File size: 8.0 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2006 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* Storage backend that uses an XMLish format for all data. */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#define BITLBEE_CORE
27#include "bitlbee.h"
28
29typedef enum
30{
31        XML_PASS_CHECK_ONLY = -1,
32        XML_PASS_UNKNOWN = 0,
33        XML_PASS_OK
34} xml_pass_st;
35
36#define XML_PASS_ERRORMSG "Wrong username or password"
37
38struct xml_parsedata
39{
40        irc_t *irc;
41        char *current_setting;
42        account_t *current_account;
43        char *given_nick;
44        char *given_pass;
45        xml_pass_st pass_st;
46};
47
48static char *xml_attr( const gchar **attr_names, const gchar **attr_values, const gchar *key )
49{
50        int i;
51       
52        for( i = 0; attr_names[i]; i ++ )
53                if( g_strcasecmp( attr_names[i], key ) == 0 )
54                        return (char*) attr_values[i];
55       
56        return NULL;
57}
58
59static void xml_destroy_xd( gpointer data )
60{
61        struct xml_parsedata *xd = data;
62       
63        g_free( xd->given_nick );
64        g_free( xd->given_pass );
65        g_free( xd );
66}
67
68static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer data, GError **error )
69{
70        struct xml_parsedata *xd = data;
71        irc_t *irc = xd->irc;
72       
73        if( g_strcasecmp( element_name, "user" ) == 0 )
74        {
75                char *nick = xml_attr( attr_names, attr_values, "nick" );
76                char *pass = xml_attr( attr_names, attr_values, "password" );
77               
78                if( !nick || !pass )
79                {
80                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
81                                     "Missing attributes for %s element", element_name );
82                }
83                else if( strcmp( nick, xd->given_nick ) == 0 &&
84                         strcmp( pass, xd->given_pass ) == 0 )
85                {
86                        if( xd->pass_st != XML_PASS_CHECK_ONLY )
87                                xd->pass_st = XML_PASS_OK;
88                }
89                else
90                {
91                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
92                                     XML_PASS_ERRORMSG );
93                }
94        }
95        else if( xd->pass_st < XML_PASS_OK )
96        {
97                /* Let's not parse anything else if we only have to check
98                   the password. */
99        }
100        else if( g_strcasecmp( element_name, "account" ) == 0 )
101        {
102                char *protocol, *handle, *server, *password;
103                struct prpl *prpl = NULL;
104               
105                handle = xml_attr( attr_names, attr_values, "handle" );
106                password = xml_attr( attr_names, attr_values, "password" );
107                server = xml_attr( attr_names, attr_values, "server" );
108               
109                protocol = xml_attr( attr_names, attr_values, "protocol" );
110                if( protocol )
111                        prpl = find_protocol( protocol );
112               
113                if( !handle || !password )
114                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
115                                     "Missing attributes for %s element", element_name );
116                else if( !prpl )
117                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
118                                     "Missing or unknown protocol %s element", element_name );
119                else
120                {
121                        xd->current_account = account_add( irc, prpl, handle, password );
122                        if( server )
123                                xd->current_account->server = g_strdup( server );
124                }
125        }
126        else if( g_strcasecmp( element_name, "setting" ) == 0 )
127        {
128                if( xd->current_account == NULL )
129                {
130                        char *setting;
131                       
132                        if( xd->current_setting )
133                        {
134                                g_free( xd->current_setting );
135                                xd->current_setting = NULL;
136                        }
137                       
138                        if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) )
139                                xd->current_setting = g_strdup( setting );
140                        else
141                                g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
142                                             "Missing attributes for %s element", element_name );
143                }
144        }
145        else if( g_strcasecmp( element_name, "buddy" ) == 0 )
146        {
147                char *handle, *nick;
148               
149                handle = xml_attr( attr_names, attr_values, "handle" );
150                nick = xml_attr( attr_names, attr_values, "nick" );
151               
152                if( xd->current_account && handle && nick )
153                {
154                        nick_set( irc, handle, xd->current_account->prpl, nick );
155                }
156                else
157                {
158                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
159                                     "Missing attributes for %s element", element_name );
160                }
161        }
162        else
163        {
164                g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
165                             "Unkown element: %s", element_name );
166        }
167}
168
169static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name, gpointer data, GError **error )
170{
171}
172
173static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_len, gpointer data, GError **error )
174{
175        struct xml_parsedata *xd = data;
176        irc_t *irc = xd->irc;
177       
178        if( xd->pass_st < XML_PASS_OK )
179        {
180                /* Let's not parse anything else if we only have to check
181                   the password. */
182        }
183        else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 &&
184                 xd->current_setting && xd->current_account == NULL )
185        {
186                set_setstr( irc, xd->current_setting, (char*) text );
187                g_free( xd->current_setting );
188                xd->current_setting = NULL;
189        }
190}
191
192static void xml_error( GMarkupParseContext *ctx, GError *error, gpointer data )
193{
194}
195
196GMarkupParser xml_parser =
197{
198        xml_start_element,
199        xml_end_element,
200        xml_text,
201        NULL,
202        xml_error
203};
204
205static void xml_init( void )
206{
207        if( access( global.conf->configdir, F_OK ) != 0 )
208                log_message( LOGLVL_WARNING, "The configuration directory %s does not exist. Configuration won't be saved.", CONFIG );
209        else if( access( global.conf->configdir, R_OK ) != 0 || access( global.conf->configdir, W_OK ) != 0 )
210                log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to %s.", global.conf->configdir );
211}
212
213static storage_status_t xml_load( const char *my_nick, const char *password, irc_t *irc )
214{
215        GMarkupParseContext *ctx;
216        struct xml_parsedata *xd;
217        char *fn, buf[512];
218        GError *gerr = NULL;
219        int fd, st;
220       
221        if( irc->status >= USTATUS_IDENTIFIED )
222                return( 1 );
223       
224        xd = g_new0( struct xml_parsedata, 1 );
225        xd->irc = irc;
226        xd->given_nick = g_strdup( my_nick );
227        xd->given_pass = g_strdup( password );
228        nick_lc( xd->given_nick );
229       
230        fn = g_strdup_printf( "%s%s%s", global.conf->configdir, xd->given_nick, ".xml" );
231        if( ( fd = open( fn, O_RDONLY ) ) < 0 )
232        {
233                xml_destroy_xd( xd );
234                g_free( fn );
235                return STORAGE_NO_SUCH_USER;
236        }
237        g_free( fn );
238       
239        ctx = g_markup_parse_context_new( &xml_parser, 0, xd, xml_destroy_xd );
240       
241        while( ( st = read( fd, buf, sizeof( buf ) ) ) > 0 )
242        {
243                if( !g_markup_parse_context_parse( ctx, buf, st, &gerr ) || gerr )
244                {
245                        g_markup_parse_context_free( ctx );
246                       
247                        /* TODO: Display useful error msg */
248                       
249                        if( gerr && strcmp( gerr->message, XML_PASS_ERRORMSG ) == 0 )
250                                return STORAGE_INVALID_PASSWORD;
251                        else
252                                return STORAGE_OTHER_ERROR;
253                }
254        }
255       
256        g_markup_parse_context_free( ctx );
257       
258        irc->status = USTATUS_IDENTIFIED;
259       
260        if( set_getint( irc, "auto_connect" ) )
261        {
262                /* Can't do this directly because r_c_s alters the string */
263                strcpy( buf, "account on" );
264                root_command_string( irc, NULL, buf, 0 );
265        }
266       
267        return STORAGE_OK;
268}
269
270static storage_status_t xml_save( irc_t *irc, int overwrite )
271{
272/*      if (!overwrite) {
273                g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
274                if (access( path, F_OK ) != -1)
275                        return STORAGE_ALREADY_EXISTS;
276       
277                g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
278                if (access( path, F_OK ) != -1)
279                        return STORAGE_ALREADY_EXISTS;
280        }
281*/     
282        return STORAGE_OK;
283}
284
285storage_t storage_xml = {
286        .name = "xml",
287        .init = xml_init,
288//      .check_pass = xml_check_pass,
289//      .remove = xml_remove,
290        .load = xml_load,
291        .save = xml_save
292};
Note: See TracBrowser for help on using the repository browser.