~ubuntu-branches/ubuntu/saucy/evolution-data-server/saucy

« back to all changes in this revision

Viewing changes to .pc/gweather_3.6.patch/calendar/backends/weather/e-weather-source-ccf.c

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2012-10-08 12:58:16 UTC
  • mfrom: (181.1.7 quantal)
  • Revision ID: package-import@ubuntu.com-20121008125816-i3n76e8c0m64e7xp
Tags: 3.6.0-0ubuntu2
* Fix LP: #1038047 part 1 - Don't abort in e_source_registry_new* when a
  problem occurs connecting to the Dbus service
  - add debian/patches/dont-abort-in-e_source_registry_new.patch
  - update debian/patches/series
* Fix LP: #1038047 part 2 - libedataserver depends on
  evolution-data-server-common to ensure that the GSettings schemas are
  present
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Evolution calendar - weather backend source class for parsing
2
 
 *      CCF (coded cities forecast) formatted NWS reports
3
 
 *
4
 
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5
 
 *
6
 
 * Authors: David Trowbridge <trowbrds@cs.colorado.edu>
7
 
 *
8
 
 * This program is free software; you can redistribute it and/or
9
 
 * modify it under the terms of version 2 of the GNU Lesser General Public
10
 
 * License as published by the Free Software Foundation.
11
 
 *
12
 
 * This program is distributed in the hope that it will be useful,
13
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
 * GNU Lesser General Public License for more details.
16
 
 *
17
 
 * You should have received a copy of the GNU Lesser General Public License
18
 
 * along with this program; if not, write to the Free Software
19
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
 
 */
21
 
 
22
 
#ifdef HAVE_CONFIG_H
23
 
#include <config.h>
24
 
#endif
25
 
 
26
 
#include <string.h>
27
 
#include <stdlib.h>
28
 
 
29
 
#include <glib/gi18n-lib.h>
30
 
 
31
 
#include "e-weather-source-ccf.h"
32
 
 
33
 
#define GWEATHER_I_KNOW_THIS_IS_UNSTABLE
34
 
#include <libgweather/weather.h>
35
 
#include <libgweather/gweather-xml.h>
36
 
#undef GWEATHER_I_KNOW_THIS_IS_UNSTABLE
37
 
 
38
 
#ifdef G_OS_WIN32
39
 
 
40
 
#ifdef localtime_r
41
 
#undef localtime_r
42
 
#endif
43
 
 
44
 
/* The localtime() in Microsoft's C library is MT-safe */
45
 
#define localtime_r(tp,tmp) (localtime(tp)?(*(tmp)=*localtime(tp),(tmp)):0)
46
 
 
47
 
/* strtok() is also MT-safe (but not stateless, still uses only one
48
 
 * buffer pointer per thread, but for the use of strtok_r() here
49
 
 * that's enough).
50
 
 */
51
 
#define strtok_r(s,sep,lasts) (*(lasts)=strtok((s),(sep)))
52
 
#endif
53
 
 
54
 
G_DEFINE_TYPE (EWeatherSourceCCF, e_weather_source_ccf, E_TYPE_WEATHER_SOURCE)
55
 
 
56
 
struct search_struct
57
 
{
58
 
        const gchar *code;
59
 
        const gchar *name;
60
 
        gboolean is_old;
61
 
        WeatherLocation *location;
62
 
};
63
 
 
64
 
static gboolean
65
 
find_location_func (GtkTreeModel *model,
66
 
                    GtkTreePath *path,
67
 
                    GtkTreeIter *node,
68
 
                    gpointer data)
69
 
{
70
 
        WeatherLocation *wl = NULL;
71
 
        struct search_struct *search = (struct search_struct *) data;
72
 
 
73
 
        gtk_tree_model_get (model, node, GWEATHER_XML_COL_POINTER, &wl, -1);
74
 
        if (!wl || !wl->name || !wl->code || !search || search->location)
75
 
                return FALSE;
76
 
 
77
 
        if (((!strcmp (wl->code, search->code)) || (search->is_old && !strcmp (wl->code + 1, search->code))) &&
78
 
             (!strcmp (wl->name, search->name))) {
79
 
                search->location = weather_location_clone (wl);
80
 
                return TRUE;
81
 
        }
82
 
 
83
 
        return FALSE;
84
 
}
85
 
 
86
 
static WeatherLocation *
87
 
find_location (const gchar *code_name,
88
 
               gboolean is_old)
89
 
{
90
 
        GtkTreeModel *model;
91
 
        gchar **ids;
92
 
        struct search_struct search;
93
 
 
94
 
        search.location = NULL;
95
 
 
96
 
        ids = g_strsplit (code_name, "/", 2);
97
 
 
98
 
        if (!ids || !ids[0] || !ids[1])
99
 
                goto done;
100
 
 
101
 
        model = gweather_xml_load_locations ();
102
 
        if (!model)
103
 
                goto done;
104
 
 
105
 
        search.code = ids[0];
106
 
        search.name = ids[1];
107
 
        search.is_old = is_old;
108
 
        search.location = NULL;
109
 
 
110
 
        gtk_tree_model_foreach (model, (GtkTreeModelForeachFunc) find_location_func, &search);
111
 
 
112
 
        gweather_xml_free_locations (model);
113
 
        g_strfreev (ids);
114
 
 
115
 
done:
116
 
        return search.location;
117
 
}
118
 
 
119
 
#if 0
120
 
static GSList *
121
 
tokenize (gchar *buffer)
122
 
{
123
 
        gchar *token;
124
 
        gchar *tokbuf;
125
 
        GSList *ret;
126
 
 
127
 
        token = strtok_r (buffer, " \n", &tokbuf);
128
 
        ret = g_slist_append (NULL, g_strdup (token));
129
 
        while ((token = strtok_r (NULL, " \n/", &tokbuf)))
130
 
                ret = g_slist_append (ret, g_strdup (token));
131
 
        return ret;
132
 
}
133
 
 
134
 
static void
135
 
date2tm (gchar *date,
136
 
         struct tm *times)
137
 
{
138
 
        gchar tmp[3];
139
 
        time_t curtime = time (NULL);
140
 
        tmp[2] = '\0';
141
 
 
142
 
        localtime_r (&curtime, times);
143
 
 
144
 
        tmp[0] = date[0]; tmp[1] = date[1];
145
 
        times->tm_mday = atoi (tmp);
146
 
        tmp[0] = date[2]; tmp[1] = date[3];
147
 
        times->tm_hour = atoi (tmp);
148
 
        tmp[0] = date[4]; tmp[1] = date[5];
149
 
        times->tm_min = atoi (tmp);
150
 
}
151
 
 
152
 
static WeatherConditions
153
 
decodeConditions (gchar code)
154
 
{
155
 
        switch (code) {
156
 
                case 'A': return WEATHER_FAIR;
157
 
                case 'B': return WEATHER_PARTLY_CLOUDY;
158
 
                case 'C': return WEATHER_CLOUDY;
159
 
                case 'D': return WEATHER_DUST;
160
 
                case 'E': return WEATHER_MOSTLY_CLOUDY;
161
 
                case 'F': return WEATHER_FOGGY;
162
 
                case 'G': return WEATHER_VERY_HOT_OR_HOT_HUMID;
163
 
                case 'H': return WEATHER_HAZE;
164
 
                case 'I': return WEATHER_VERY_COLD_WIND_CHILL;
165
 
                case 'J': return WEATHER_SNOW_SHOWERS;
166
 
                case 'K': return WEATHER_SMOKE;
167
 
                case 'L': return WEATHER_DRIZZLE;
168
 
                case 'M': return WEATHER_SNOW_SHOWERS;
169
 
                case 'N': return WEATHER_WINDY;
170
 
                case 'O': return WEATHER_RAIN_OR_SNOW_MIXED;
171
 
                case 'P': return WEATHER_BLIZZARD;
172
 
                case 'Q': return WEATHER_BLOWING_SNOW;
173
 
                case 'R': return WEATHER_RAIN;
174
 
                case 'S': return WEATHER_SNOW;
175
 
                case 'T': return WEATHER_THUNDERSTORMS;
176
 
                case 'U': return WEATHER_SUNNY;
177
 
                case 'V': return WEATHER_CLEAR;
178
 
                case 'W': return WEATHER_RAIN_SHOWERS;
179
 
                case 'X': return WEATHER_SLEET;
180
 
                case 'Y': return WEATHER_FREEZING_RAIN;
181
 
                case 'Z': return WEATHER_FREEZING_DRIZZLE;
182
 
                /* hmm, this should never happen. */
183
 
                default: return WEATHER_SUNNY;
184
 
        }
185
 
}
186
 
 
187
 
static gint
188
 
decodePOP (gchar data)
189
 
{
190
 
        gint ret;
191
 
 
192
 
        switch (data) {
193
 
                case '-':
194
 
                        ret = 5;
195
 
                        break;
196
 
                case '+':
197
 
                        ret = 95;
198
 
                        break;
199
 
                case '/':
200
 
                        ret = -1;       /* missing data */
201
 
                        break;
202
 
                default:
203
 
                        ret = (data - '0') * 10;
204
 
        }
205
 
        return ret;
206
 
}
207
 
 
208
 
static void
209
 
decodeSnowfall (gchar *data,
210
 
                gfloat *low,
211
 
                gfloat *high)
212
 
{
213
 
        gchar num[3];
214
 
        num[2] = '\0';
215
 
 
216
 
        num[0] = data[0]; num[1] = data[1];
217
 
        *low = atof (num) * 2.54f;
218
 
        num[0] = data[2]; num[1] = data[3];
219
 
        *high = atof (num) * 2.54f;
220
 
}
221
 
 
222
 
static float
223
 
ftoc (gchar *data)
224
 
{
225
 
        gint fahrenheit = atoi (data);
226
 
        if (fahrenheit >= 900)
227
 
                fahrenheit = (fahrenheit - 900) * -1;
228
 
        return ((gfloat)(fahrenheit - 32)) * 5.0f / 9.0f;
229
 
}
230
 
 
231
 
static void
232
 
e_weather_source_ccf_do_parse (EWeatherSourceCCF *source,
233
 
                               gchar *buffer)
234
 
{
235
 
        /* CCF gives us either 2 or 7 days of forecast data. IFPS WFO's
236
 
         * will produce 7 day forecasts, whereas pre-IFPS WFO's are only
237
 
         * mandated 2 (but may do 7). The morning forecast will give us either 2
238
 
         * or 7 days worth of data. The evening forecast will give us the evening's
239
 
         * low temperature plus 2 or 7 days forecast.
240
 
         *
241
 
         * The CCF format is described in NWS directive 10-503, but it's usually
242
 
         * easier to look at a summary put up by one of the stations:
243
 
         * http://www.crh.noaa.gov/lmk/product_guide/products/forecast/ccf.htm
244
 
         */
245
 
        WeatherForecast *forecasts = g_new0 (WeatherForecast, 7);
246
 
        GSList *tokens = tokenize (buffer);
247
 
        GSList *date;
248
 
        GSList *current = tokens;
249
 
        GList *fc = NULL;
250
 
        struct tm tms;
251
 
        gint i;
252
 
        time_t base;
253
 
        gint n;
254
 
 
255
 
        date = g_slist_nth (tokens, 3);
256
 
        date2tm (date->data, &tms);
257
 
 
258
 
        /* fast-forward to the particular station we're interested in */
259
 
        current = g_slist_nth (tokens, 5);
260
 
        while (strcmp (current->data, source->substation))
261
 
                current = g_slist_next (current);
262
 
        current = g_slist_next (current);
263
 
        /* pick up the first two conditions reports */
264
 
        forecasts[0].conditions = decodeConditions (((gchar *)(current->data))[0]);
265
 
        forecasts[1].conditions = decodeConditions (((gchar *)(current->data))[1]);
266
 
 
267
 
        current = g_slist_next (current);
268
 
        if (tms.tm_hour < 12) {
269
 
                for (i = 0; i < 2; i++) {
270
 
                        forecasts[i].high = ftoc (current->data);
271
 
                        current = g_slist_next (current);
272
 
                        forecasts[i].low  = ftoc (current->data);
273
 
                        current = g_slist_next (current);
274
 
                }
275
 
                forecasts[2].high = ftoc (current->data);
276
 
                current = g_slist_next (current);
277
 
                forecasts[0].pop = decodePOP (((gchar *)(current->data))[2]);
278
 
                forecasts[1].pop = decodePOP (((gchar *)(current->data))[4]);
279
 
        } else {
280
 
                for (i = 0; i < 2; i++) {
281
 
                        current = g_slist_next (current);
282
 
                        forecasts[i].high = ftoc (current->data);
283
 
                        current = g_slist_next (current);
284
 
                        forecasts[i].low  = ftoc (current->data);
285
 
                }
286
 
                current = g_slist_next (current);
287
 
                forecasts[0].pop = decodePOP (((gchar *)(current->data))[1]);
288
 
                forecasts[1].pop = decodePOP (((gchar *)(current->data))[3]);
289
 
        }
290
 
 
291
 
        current = g_slist_next (current);
292
 
        if (strlen (current->data) == 4) {
293
 
                /* we've got the optional snowfall field */
294
 
                if (tms.tm_hour < 12) {
295
 
                        decodeSnowfall (current->data, &forecasts[0].low, &forecasts[0].high);
296
 
                        current = g_slist_next (g_slist_next (current));
297
 
                        decodeSnowfall (current->data, &forecasts[1].low, &forecasts[1].high);
298
 
                } else {
299
 
                        current = g_slist_next (current);
300
 
                        decodeSnowfall (current->data, &forecasts[0].low, &forecasts[0].high);
301
 
                }
302
 
                current = g_slist_next (current);
303
 
        }
304
 
 
305
 
        /* set dates */
306
 
        base = mktime (&tms);
307
 
        if (tms.tm_hour >= 12)
308
 
                base += 43200;
309
 
        for (i = 0; i < 7; i++)
310
 
                forecasts[i].date = base + 86400 * i;
311
 
 
312
 
        if (current == NULL || strlen (current->data) == 3) {
313
 
                /* We've got a pre-IFPS station. Realloc and return */
314
 
                WeatherForecast *f = g_new0 (WeatherForecast, 2);
315
 
                memcpy (f, forecasts, sizeof (WeatherForecast) * 2);
316
 
                fc = g_list_append (fc, &f[0]);
317
 
                fc = g_list_append (fc, &f[1]);
318
 
                source->done (fc, source->finished_data);
319
 
        }
320
 
 
321
 
        /* Grab the conditions for the next 5 days */
322
 
        forecasts[2].conditions = decodeConditions (((gchar *)(current->data))[0]);
323
 
        forecasts[3].conditions = decodeConditions (((gchar *)(current->data))[1]);
324
 
        forecasts[4].conditions = decodeConditions (((gchar *)(current->data))[2]);
325
 
        forecasts[5].conditions = decodeConditions (((gchar *)(current->data))[3]);
326
 
        forecasts[6].conditions = decodeConditions (((gchar *)(current->data))[4]);
327
 
 
328
 
        /* Temperature forecasts */
329
 
        current = g_slist_next (current);
330
 
        if (tms.tm_hour < 12) {
331
 
                forecasts[2].low  = ftoc (current->data);
332
 
                for  (i = 3; i < 6; i++) {
333
 
                        current = g_slist_next (current);
334
 
                        forecasts[i].high = ftoc (current->data);
335
 
                        current = g_slist_next (current);
336
 
                        forecasts[i].low  = ftoc (current->data);
337
 
                }
338
 
                current = g_slist_next (current);
339
 
                forecasts[6].high = ftoc (current->data);
340
 
                forecasts[6].low  = forecasts[6].high;
341
 
                current = g_slist_next (current);
342
 
                forecasts[2].pop = decodePOP (((gchar *)(current->data))[1]);
343
 
                forecasts[3].pop = decodePOP (((gchar *)(current->data))[3]);
344
 
                forecasts[4].pop = decodePOP (((gchar *)(current->data))[5]);
345
 
                forecasts[5].pop = decodePOP (((gchar *)(current->data))[7]);
346
 
                forecasts[6].pop = decodePOP (((gchar *)(current->data))[9]);
347
 
                n = 7;
348
 
        } else {
349
 
                for (i = 2; i < 6; i++) {
350
 
                        forecasts[i].high = ftoc (current->data);
351
 
                        current = g_slist_next (current);
352
 
                        forecasts[i].low  = ftoc (current->data);
353
 
                        current = g_slist_next (current);
354
 
                }
355
 
                n = 6;
356
 
                /* hack for people who put out bad data, like Pueblo, CO. Yes, PUB, that means you */
357
 
                if (strlen (current->data) == 3)
358
 
                        current = g_slist_next (current);
359
 
                forecasts[1].pop = decodePOP (((gchar *)(current->data))[0]);
360
 
                forecasts[2].pop = decodePOP (((gchar *)(current->data))[2]);
361
 
                forecasts[3].pop = decodePOP (((gchar *)(current->data))[4]);
362
 
                forecasts[4].pop = decodePOP (((gchar *)(current->data))[6]);
363
 
                forecasts[5].pop = decodePOP (((gchar *)(current->data))[8]);
364
 
        }
365
 
 
366
 
        for (i = 0; i < n; i++) {
367
 
                fc = g_list_append (fc, &forecasts[i]);
368
 
        }
369
 
        source->done (fc, source->finished_data);
370
 
 
371
 
        g_free (forecasts);
372
 
        g_list_free (fc);
373
 
}
374
 
#endif
375
 
 
376
 
static void
377
 
parse_done (WeatherInfo *info,
378
 
            gpointer data)
379
 
{
380
 
        EWeatherSourceCCF *ccfsource = (EWeatherSourceCCF *) data;
381
 
 
382
 
        if (!ccfsource)
383
 
                return;
384
 
 
385
 
        if (!info || !weather_info_is_valid (info)) {
386
 
                ccfsource->done (NULL, ccfsource->finished_data);
387
 
                return;
388
 
        }
389
 
 
390
 
        ccfsource->done (info, ccfsource->finished_data);
391
 
}
392
 
 
393
 
static void
394
 
e_weather_source_ccf_parse (EWeatherSource *source,
395
 
                            EWeatherSourceFinished done,
396
 
                            gpointer data)
397
 
{
398
 
        EWeatherSourceCCF *ccfsource = (EWeatherSourceCCF *) source;
399
 
        WeatherPrefs prefs;
400
 
 
401
 
        ccfsource->finished_data = data;
402
 
        ccfsource->done = done;
403
 
 
404
 
        prefs.type = FORECAST_LIST;
405
 
        prefs.radar = FALSE;
406
 
        prefs.radar_custom_url = NULL;
407
 
        prefs.temperature_unit = TEMP_UNIT_CENTIGRADE;
408
 
        prefs.speed_unit = SPEED_UNIT_MS;
409
 
        prefs.pressure_unit = PRESSURE_UNIT_HPA;
410
 
        prefs.distance_unit = DISTANCE_UNIT_METERS;
411
 
 
412
 
        if (ccfsource->location && !ccfsource->info) {
413
 
                ccfsource->info = weather_info_new (ccfsource->location, &prefs, parse_done, source);
414
 
                weather_location_free (ccfsource->location);
415
 
                ccfsource->location = NULL;
416
 
        } else {
417
 
                ccfsource->info = weather_info_update (ccfsource->info, &prefs, parse_done, source);
418
 
        }
419
 
}
420
 
 
421
 
static void
422
 
e_weather_source_ccf_class_init (EWeatherSourceCCFClass *class)
423
 
{
424
 
        EWeatherSourceClass *source_class;
425
 
 
426
 
        source_class = E_WEATHER_SOURCE_CLASS (class);
427
 
        source_class->parse = e_weather_source_ccf_parse;
428
 
}
429
 
 
430
 
static void
431
 
e_weather_source_ccf_init (EWeatherSourceCCF *source)
432
 
{
433
 
        source->location = NULL;
434
 
        source->info = NULL;
435
 
}
436
 
 
437
 
EWeatherSource *
438
 
e_weather_source_ccf_new (const gchar *location)
439
 
{
440
 
        /* Old location is formatted as ccf/AAA[/BBB] - AAA is the 3-letter
441
 
         * station code for identifying the providing station (subdirectory
442
 
         * within the crh data repository). BBB is an optional additional
443
 
         * station ID for the station within the CCF file. If not present,
444
 
         * BBB is assumed to be the same station as AAA.  But the new
445
 
         * location is code/name, where code is 4-letter code.  So if we
446
 
         * got the old format, then migrate to the new one, if possible.
447
 
         */
448
 
 
449
 
        WeatherLocation *wl;
450
 
        EWeatherSourceCCF *source;
451
 
 
452
 
        if (location == NULL)
453
 
                return NULL;
454
 
 
455
 
        if (strncmp (location, "ccf/", 4) == 0)
456
 
                wl = find_location (location + 4, TRUE);
457
 
        else
458
 
                wl = find_location (location, FALSE);
459
 
 
460
 
        if (wl == NULL)
461
 
                return NULL;
462
 
 
463
 
        source = g_object_new (E_TYPE_WEATHER_SOURCE_CCF, NULL);
464
 
        source->location = wl;
465
 
        source->info = NULL;
466
 
 
467
 
        return E_WEATHER_SOURCE (source);
468
 
}