00001
00027
00028
00029 #include "internal.h"
00030 #include <string.h>
00031 #include "debug.h"
00032 #include "prefs.h"
00033
00034 #include "utils.h"
00035 #include "ip_location.h"
00036
00037 #define DEFAULT_IP_LOCATION_FILE "gaim/QQWry.dat"
00038
00039 typedef struct _ip_finder ip_finder;
00040
00041
00042 struct _ip_finder {
00043 guint32 offset_first_start_ip;
00044 guint32 offset_last_start_ip;
00045 guint32 cur_start_ip;
00046 guint32 cur_end_ip;
00047 guint32 offset_cur_end_ip;
00048 GIOChannel *io;
00049 };
00050
00051
00052
00053
00054 guint32 _byte_array_to_int(guint8 * ip, gint count)
00055 {
00056 guint32 ret, i;
00057 g_return_val_if_fail(count >= 1 && count <= 4, 0);
00058 ret = ip[0];
00059 for (i = 0; i < count; i++)
00060 ret |= ((guint32) ip[i]) << (8 * i);
00061 return ret;
00062 }
00063
00064
00065
00066 void _read_from(GIOChannel * io, guint32 offset, guint8 * buf, gint len)
00067 {
00068 GError *err;
00069 GIOStatus status;
00070
00071 err = NULL;
00072 status = g_io_channel_seek_position(io, offset, G_SEEK_SET, &err);
00073 if (err != NULL) {
00074 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Fail seek file @offset[%d]: %s", offset, err->message);
00075 g_error_free(err);
00076 memset(buf, 0, len);
00077 return;
00078 }
00079
00080 status = g_io_channel_read_chars(io, buf, len, NULL, &err);
00081 if (err != NULL) {
00082 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Fail read %d bytes from file: %s", len, err->message);
00083 g_error_free(err);
00084 memset(buf, 0, len);
00085 return;
00086 }
00087 }
00088
00089
00090
00091 gsize _read_line_from(GIOChannel * io, guint32 offset, gchar ** ret_str)
00092 {
00093 gsize bytes_read;
00094 GError *err;
00095 GIOStatus status;
00096
00097 err = NULL;
00098 status = g_io_channel_seek_position(io, offset, G_SEEK_SET, &err);
00099 if (err != NULL) {
00100 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Fail seek file @offset[%d]: %s", offset, err->message);
00101 g_error_free(err);
00102 ret_str = NULL;
00103 return -1;
00104 }
00105
00106 status = g_io_channel_read_line(io, ret_str, &bytes_read, NULL, &err);
00107 if (err != NULL) {
00108 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Fail read from file: %s", err->message);
00109 g_error_free(err);
00110 ret_str = NULL;
00111 return -1;
00112 }
00113
00114 return bytes_read;
00115 }
00116
00117
00118
00119
00120 guint32 _get_string(GIOChannel * io, guint32 offset, gchar ** ret)
00121 {
00122 guint8 *buf;
00123 g_return_val_if_fail(io != NULL, 0);
00124
00125 buf = g_new0(guint8, 3);
00126 _read_from(io, offset, buf, 1);
00127
00128 switch (buf[0]) {
00129 case 0x01:
00130 _read_from(io, offset + 1, buf, 3);
00131 return _get_string(io, _byte_array_to_int(buf, 3), ret);
00132 case 0x02:
00133 _read_from(io, offset + 1, buf, 3);
00134 _get_string(io, _byte_array_to_int(buf, 3), ret);
00135 return offset + 4;
00136 default:
00137 _read_line_from(io, offset, ret);
00138 return offset + strlen(*ret) + 1;
00139 }
00140 }
00141
00142
00143
00144 void _get_country_city(GIOChannel * io, guint32 offset, gchar ** country, gchar ** area)
00145 {
00146 guint32 next_offset;
00147 g_return_if_fail(io != NULL);
00148
00149 next_offset = _get_string(io, offset, country);
00150 if (next_offset == 0)
00151 *area = g_strdup("");
00152 else
00153 _get_string(io, next_offset, area);
00154 }
00155
00156
00157
00158 void _set_ip_range(gint rec_no, ip_finder * f)
00159 {
00160 guint8 *buf;
00161 guint32 offset;
00162
00163 g_return_if_fail(f != NULL);
00164
00165 buf = g_newa(guint8, 7);
00166 offset = f->offset_first_start_ip + rec_no * 7;
00167
00168 _read_from(f->io, offset, buf, 7);
00169 f->cur_start_ip = _byte_array_to_int(buf, 4);
00170 f->offset_cur_end_ip = _byte_array_to_int(buf + 4, 3);
00171
00172 _read_from(f->io, f->offset_cur_end_ip, buf, 4);
00173 f->cur_end_ip = _byte_array_to_int(buf, 4);
00174
00175 }
00176
00177
00178
00179
00180 gboolean qq_ip_get_location(guint32 ip, gchar ** country, gchar ** area)
00181 {
00182 gint rec, record_count, B, E;
00183 guint8 *buf;
00184 gchar *addr_file;
00185 ip_finder *f;
00186 GError *err;
00187 const char *ip_fn;
00188
00189 if (ip == 0)
00190 return FALSE;
00191
00192 f = g_new0(ip_finder, 1);
00193 err = NULL;
00194 ip_fn = gaim_prefs_get_string("/plugins/prpl/qq/ipfile");
00195 if (ip_fn == NULL || strlen(ip_fn) == 0 || strncmp(ip_fn, "(null)", strlen("(null)")) == 0) {
00196 addr_file = g_build_filename(DATADIR, DEFAULT_IP_LOCATION_FILE, NULL);
00197 } else {
00198 addr_file = g_build_filename(ip_fn, NULL);
00199 }
00200
00201 f->io = g_io_channel_new_file(addr_file, "r", &err);
00202 g_free(addr_file);
00203 if (err != NULL) {
00204 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Unable to open (%s): %s\n", addr_file, err->message);
00205 g_error_free(err);
00206 return FALSE;
00207 } else
00208 g_io_channel_set_encoding(f->io, NULL, NULL);
00209
00210 buf = g_newa(guint8, 4);
00211
00212 _read_from(f->io, 0, buf, 4);
00213 f->offset_first_start_ip = _byte_array_to_int(buf, 4);
00214 _read_from(f->io, 4, buf, 4);
00215 f->offset_last_start_ip = _byte_array_to_int(buf, 4);
00216
00217 record_count = (f->offset_last_start_ip - f->offset_first_start_ip) / 7;
00218 if (record_count <= 1) {
00219 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "File data error, no records found\n");
00220 g_io_channel_shutdown(f->io, FALSE, NULL);
00221 return FALSE;;
00222 }
00223
00224 B = 0;
00225 E = record_count;
00226 while (B < E - 1) {
00227 rec = (B + E) / 2;
00228 _set_ip_range(rec, f);
00229 if (ip == f->cur_start_ip) {
00230 B = rec;
00231 break;
00232 }
00233 if (ip > f->cur_start_ip)
00234 B = rec;
00235 else
00236 E = rec;
00237 }
00238 _set_ip_range(B, f);
00239
00240 if (f->cur_start_ip <= ip && ip <= f->cur_end_ip) {
00241 _get_country_city(f->io, f->offset_cur_end_ip + 4, country, area);
00242 } else {
00243 *country = g_strdup("unkown");
00244 *area = g_strdup(" ");
00245 }
00246
00247 g_io_channel_shutdown(f->io, FALSE, NULL);
00248 return TRUE;
00249
00250 }
00251
00252
00253