Mercurial > pidgin
annotate src/status.c @ 8150:20262ccefdd8
[gaim-migrate @ 8862]
Nope, it's humor. Trust me, I know--I define it.
Oh, also, this should make oscar ssi lists take precedence over
local lists. So if you sign on while you're in Rome and delete
someone, the next time you sign in with Gaim the dude will be
deleted from your local list as well.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Tue, 20 Jan 2004 15:27:33 +0000 |
parents | fa6395637e2c |
children | f24172f53650 |
rev | line source |
---|---|
6065 | 1 /* |
2 * gaim | |
3 * | |
8046 | 4 * Gaim is the legal property of its developers, whose names are too numerous |
5 * to list here. Please refer to the COPYRIGHT file distributed with this | |
6 * source distribution. | |
6065 | 7 * |
8 * This program is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 */ | |
22 | |
23 #include "status.h" | |
24 #include "internal.h" | |
25 #include "debug.h" | |
26 #include "util.h" | |
27 | |
6371
8f94cce8faa5
[gaim-migrate @ 6876]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
28 /* XXX CORE/UI */ |
8f94cce8faa5
[gaim-migrate @ 6876]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
29 #include "gtkinternal.h" |
8f94cce8faa5
[gaim-migrate @ 6876]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
30 #include "ui.h" |
8f94cce8faa5
[gaim-migrate @ 6876]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
31 |
8f94cce8faa5
[gaim-migrate @ 6876]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
32 |
6065 | 33 /* for people like myself who are too lazy to add an away msg :) */ |
34 /* I don't know who "myself" is in this context. The exclamation point | |
35 * makes it slightly less boring ;) */ | |
36 #define BORING_DEFAULT_AWAY_MSG _("Sorry, I ran out for a bit!") | |
37 | |
38 /* XML File Saving */ | |
39 | |
40 /* All of this code is adapted from Nathan Walp's. It's adapted all over the place | |
41 * for accounts, the buddy list, pounces, preferences, and the likes. It would be | |
42 * neat if we could somehow make this more generic. */ | |
43 static gboolean status_loaded = FALSE; | |
44 static guint status_save_timer = 0; | |
45 | |
46 | |
47 typedef enum | |
48 { | |
49 TAG_NONE = 0, | |
50 TAG_STATUS, | |
51 TAG_STATE, | |
52 TAG_MESSAGE, | |
53 | |
54 } StatusParserTag; | |
55 | |
56 | |
57 typedef struct | |
58 { | |
59 StatusParserTag tag; | |
60 GString *buffer; | |
61 struct away_message *am; | |
62 | |
63 } StatusParserData; | |
64 | |
65 static void | |
66 free_parser_data(gpointer user_data) | |
67 { | |
68 StatusParserData *data = user_data; | |
69 | |
70 if (data->buffer != NULL) | |
71 g_string_free(data->buffer, TRUE); | |
72 | |
73 g_free(data); | |
74 } | |
75 | |
76 static void gaim_status_write(FILE *fp, struct away_message *am) | |
77 { | |
78 char *esc = NULL; | |
6216 | 79 |
6065 | 80 esc = g_markup_escape_text(am->name, -1); |
6216 | 81 fprintf(fp, "\t<status name=\"%s\">\n", esc); |
6065 | 82 g_free(esc); |
83 | |
6216 | 84 fprintf(fp, "\t\t<state>away</state>\n"); |
85 | |
86 esc = g_markup_escape_text(am->message, -1); | |
87 fprintf(fp, "\t\t<message>%s</message>\n", esc); | |
88 g_free(esc); | |
89 | |
90 fprintf(fp, "\t</status>\n"); | |
6065 | 91 } |
92 | |
93 static gboolean | |
94 status_save_cb(gpointer unused) | |
95 { | |
96 gaim_status_sync(); | |
97 status_save_timer = 0; | |
98 | |
99 return FALSE; | |
100 } | |
101 | |
102 static void | |
103 schedule_status_save() | |
104 { | |
105 if (!status_save_timer) | |
106 status_save_timer = g_timeout_add(5000, status_save_cb, NULL); | |
107 } | |
108 | |
109 static void | |
110 start_element_handler(GMarkupParseContext *context, | |
111 const gchar *element_name, | |
112 const gchar **attribute_names, | |
113 const gchar **attribute_values, | |
114 gpointer user_data, GError **error) | |
115 { | |
116 const char *value; | |
117 StatusParserData *data = user_data; | |
118 GHashTable *atts; | |
119 int i; | |
120 | |
121 atts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
122 | |
123 for (i = 0; attribute_names[i] != NULL; i++) { | |
124 g_hash_table_insert(atts, g_strdup(attribute_names[i]), | |
125 g_strdup(attribute_values[i])); | |
126 } | |
127 | |
128 if (data->buffer != NULL) { | |
129 g_string_free(data->buffer, TRUE); | |
130 data->buffer = NULL; | |
131 } | |
132 | |
133 if (!strcmp(element_name, "status")) { | |
134 data->tag = TAG_STATUS; | |
135 if ((value = g_hash_table_lookup(atts, "name")) != NULL) { | |
136 data->am = g_new0(struct away_message, 1); | |
137 g_snprintf(data->am->name, sizeof(data->am->name), "%s", value); | |
138 away_messages = g_slist_append(away_messages, data->am); | |
139 } | |
140 } else if (!strcmp(element_name, "message")) { | |
141 data->tag = TAG_MESSAGE; | |
6216 | 142 |
6065 | 143 } |
6113 | 144 |
145 g_hash_table_destroy(atts); | |
6065 | 146 } |
147 | |
148 static void | |
149 end_element_handler(GMarkupParseContext *context, const gchar *element_name, | |
150 gpointer user_data, GError **error) | |
151 { | |
152 StatusParserData *data = user_data; | |
153 gchar *buffer; | |
154 | |
155 if (data->buffer == NULL) | |
156 return; | |
157 | |
158 buffer = g_string_free(data->buffer, FALSE); | |
159 data->buffer = NULL; | |
160 | |
161 if (data->tag == TAG_MESSAGE) { | |
162 if (*buffer != '\0') | |
163 g_snprintf(data->am->message, sizeof(data->am->message), "%s", buffer); | |
164 } | |
165 | |
166 data->tag = TAG_NONE; | |
167 | |
168 g_free(buffer); | |
169 } | |
170 | |
171 static void | |
172 text_handler(GMarkupParseContext *context, const gchar *text, | |
173 gsize text_len, gpointer user_data, GError **error) | |
174 { | |
175 StatusParserData *data = user_data; | |
176 | |
177 if (data->buffer == NULL) | |
178 data->buffer = g_string_new_len(text, text_len); | |
179 else | |
180 g_string_append_len(data->buffer, text, text_len); | |
181 } | |
182 | |
183 static GMarkupParser status_parser = | |
184 { | |
185 start_element_handler, | |
186 end_element_handler, | |
187 text_handler, | |
188 NULL, | |
189 NULL | |
190 }; | |
191 | |
192 void gaim_status_sync() | |
193 { | |
194 FILE *fp; | |
195 const char *user_dir = gaim_user_dir(); | |
196 char *filename, *filename_real; | |
197 | |
198 if (!status_loaded) { | |
199 gaim_debug(GAIM_DEBUG_WARNING, "status", "Writing status to disk.\n"); | |
200 schedule_status_save(); | |
201 return; | |
202 } | |
203 | |
204 if (user_dir == NULL) | |
205 return; | |
206 | |
207 gaim_debug(GAIM_DEBUG_INFO, "status", "Saving statuses to disk\n"); | |
208 | |
209 fp = fopen(user_dir, "r"); | |
210 | |
211 if (fp == NULL) | |
212 mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR); | |
213 else | |
214 fclose(fp); | |
215 | |
216 filename = g_build_filename(user_dir, "status.xml.save", NULL); | |
217 | |
218 if ((fp = fopen(filename, "w")) != NULL) { | |
219 GSList *l; | |
220 | |
221 fprintf(fp, "<?xml version='1.0' encoding='UTF-8' ?>\n\n"); | |
222 fprintf(fp, "<statuses>\n"); | |
223 | |
224 for (l = away_messages; l != NULL; l = l->next) | |
225 gaim_status_write(fp, l->data); | |
226 | |
227 fprintf(fp, "</statuses>\n"); | |
228 | |
229 fclose(fp); | |
230 chmod(filename, S_IRUSR | S_IWUSR); | |
231 } | |
232 else { | |
233 gaim_debug(GAIM_DEBUG_ERROR, "status", "Unable to write %s\n", | |
234 filename); | |
235 } | |
236 | |
237 filename_real = g_build_filename(user_dir, "status.xml", NULL); | |
238 | |
239 if (rename(filename, filename_real) < 0) { | |
240 gaim_debug(GAIM_DEBUG_ERROR, "status", "Error renaming %s to %s\n", | |
241 filename, filename_real); | |
242 } | |
243 | |
244 g_free(filename); | |
245 g_free(filename_real); | |
246 | |
247 } | |
248 | |
249 void gaim_status_load() | |
250 { | |
251 gchar *filename = g_build_filename(gaim_user_dir(), "status.xml", NULL); | |
252 gchar *contents = NULL; | |
253 gsize length; | |
254 GMarkupParseContext *context; | |
255 GError *error = NULL; | |
256 StatusParserData *parser_data; | |
257 | |
258 if (filename == NULL) { | |
259 status_loaded = TRUE; | |
260 return; | |
261 } | |
262 | |
263 if (!g_file_get_contents(filename, &contents, &length, &error)) { | |
264 gaim_debug(GAIM_DEBUG_ERROR, "status", | |
265 "Error reading statuses: %s\n", error->message); | |
266 g_error_free(error); | |
267 g_free(filename); | |
268 status_loaded = TRUE; | |
269 if (!away_messages) { | |
270 struct away_message *a = g_new0(struct away_message, 1); | |
271 g_snprintf(a->name, sizeof(a->name), _("Slightly less boring default")); | |
6321 | 272 g_snprintf(a->message, sizeof(a->message), "%s", _(BORING_DEFAULT_AWAY_MSG)); |
6065 | 273 away_messages = g_slist_append(away_messages, a); |
274 } | |
275 return; | |
276 } | |
277 | |
278 parser_data = g_new0(StatusParserData, 1); | |
279 | |
280 context = g_markup_parse_context_new(&status_parser, 0, | |
281 parser_data, free_parser_data); | |
282 | |
283 if (!g_markup_parse_context_parse(context, contents, length, NULL)) { | |
284 g_markup_parse_context_free(context); | |
285 g_free(contents); | |
286 g_free(filename); | |
287 status_loaded = TRUE; | |
288 return; | |
289 } | |
290 | |
291 if (!g_markup_parse_context_end_parse(context, NULL)) { | |
292 gaim_debug(GAIM_DEBUG_ERROR, "status", "Error parsing %s\n", | |
293 filename); | |
294 g_markup_parse_context_free(context); | |
295 g_free(contents); | |
296 g_free(filename); | |
297 status_loaded = TRUE; | |
298 return; | |
299 } | |
300 | |
301 g_markup_parse_context_free(context); | |
302 g_free(contents); | |
303 g_free(filename); | |
304 status_loaded = TRUE; | |
305 return; | |
306 } |