首页 | 数据结构 | 文件列表 | 数据字段 | 全局定义

ip_location.c

浏览该文件的文档。
00001 
00027 // START OF FILE
00028 /*****************************************************************************/
00029 #include "internal.h"
00030 #include <string.h>             // memset
00031 #include "debug.h"
00032 #include "prefs.h"              // gaim_prefs_get_string
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 // all offset is based the begining of the file
00042 struct _ip_finder {
00043         guint32 offset_first_start_ip;  // first abs offset of start ip
00044         guint32 offset_last_start_ip;   // last abs offset of start ip
00045         guint32 cur_start_ip;   // start ip of current search range
00046         guint32 cur_end_ip;     // end ip of current search range
00047         guint32 offset_cur_end_ip;      // where is the current end ip saved
00048         GIOChannel *io;         // IO Channel to read file
00049 };                              // struct _ip_finder
00050 
00051 /*****************************************************************************/
00052 // convert 1-4 bytes array to integer.
00053 // Small endian (higher bytes in lower place)
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 }                               // _byte_array_to_int
00063 
00064 /*****************************************************************************/
00065 // read len of bytes to buf, from io at offset
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         }                       // if err
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         }                       // if err
00087 }                               // _read_from
00088 
00089 /*****************************************************************************/
00090 // read len of bytes to buf, from io at offset
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         }                       // if err
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         }                       // if err
00113 
00114         return bytes_read;
00115 }                               // _read_from
00116 
00117 /*****************************************************************************/
00118 // read the string from io, at offset, it may jump several times
00119 // returns the offset of next readable string for area
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]) {       /* fixed by bluestar11 at gmail dot com, 04/12/20 */
00129         case 0x01:              /* jump together */
00130           _read_from(io, offset + 1, buf, 3);
00131           return _get_string(io, _byte_array_to_int(buf, 3), ret);
00132         case 0x02:              /* jump separately */
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         } /* switch */
00140 }                               // _get_string
00141 
00142 /*****************************************************************************/
00143 // extract country and area starting from offset
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 }                               // _get_country_city
00155 
00156 /*****************************************************************************/
00157 // set start_ip and end_ip of current range
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 }                               // _set_ip_range
00176 
00177 /*****************************************************************************/
00178 // set the country and area for given IP.
00179 // country and area needs to be freed later
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);   // set binary
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         // search for right range
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         }                       // while
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 {                // not in this range... miss
00243                 *country = g_strdup("unkown");
00244                 *area = g_strdup(" ");
00245         }                       // if ip_start<=ip<=ip_end
00246 
00247         g_io_channel_shutdown(f->io, FALSE, NULL);
00248         return TRUE;
00249 
00250 }                               // qq_ip_get_location
00251 
00252 /*****************************************************************************/
00253 // END OF FILE

Generated at Mon May 8 15:41:24 2006 for OpenQ by  doxygen 1.4.4