far from being complete:
authorulfl <ulfl@f5534014-38df-0310-8fa8-9805f1628bb7>
Sat, 13 Jan 2007 14:33:46 +0000 (14:33 +0000)
committerulfl <ulfl@f5534014-38df-0310-8fa8-9805f1628bb7>
Sat, 13 Jan 2007 14:33:46 +0000 (14:33 +0000)
as mentioned on the devel list, this is a very first start of implementing the Wireshark update/version check feature

think of it as a backup / discussion base only - it's not even added to the Makefiles yet

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@20415 f5534014-38df-0310-8fa8-9805f1628bb7

nio-ie5.c [new file with mode: 0644]
nio-ie5.h [new file with mode: 0644]
update.c [new file with mode: 0644]

diff --git a/nio-ie5.c b/nio-ie5.c
new file mode 100644 (file)
index 0000000..9ad0b72
--- /dev/null
+++ b/nio-ie5.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2000, Red Hat, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     A copy of the GNU General Public License can be found at
+ *     http://www.gnu.org/
+ *
+ * Written by DJ Delorie <dj@cygnus.com>
+ * Modified by Ulf Lamping to meet Wireshark use
+ *
+ */
+
+/* The purpose of this file is to manage internet downloads using the
+   Internet Explorer version 5 DLLs.  To use this method, the user
+   must already have installed and configured IE5.  */
+
+#include "windows.h"\r
+#include <wininet.h>\r
+#include "nio-ie5.h"\r
+\r
+#include "glib.h"\r
+
+static HINTERNET internet = 0;\r
+\r
+
+
+netio_ie5_t * 
+netio_ie5_connect (char const *url)
+{
+  int resend = 0;
+  DWORD type, type_s;\r
+  netio_ie5_t * netio_ie5_conn;\r
+  DWORD dw_ret;\r
+  DWORD flags =\r
+ /*    INTERNET_FLAG_DONT_CACHE |*/\r
+    INTERNET_FLAG_KEEP_CONNECTION |\r
+ /*   INTERNET_FLAG_PRAGMA_NOCACHE |*/\r
+ /*   INTERNET_FLAG_RELOAD |*/\r
+    INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_PASSIVE;\r
+\r
+  if (internet == 0)
+    {
+      HINSTANCE h = LoadLibrary ("wininet.dll");
+      if (!h)
+       {\r
+          /* XXX - how to return an error code? */
+          g_warning("Failed to load wininet.dll");
+         return NULL;
+       }\r
+      /* pop-up dialup dialog box */\r
+      /* XXX - do we need the dialup box or simply don't attempt an update in this case? */\r
+      dw_ret = InternetAttemptConnect (0);
+      if (dw_ret != ERROR_SUCCESS) {\r
+        g_warning("InternetAttemptConnect failed: %u", dw_ret);\r
+        return NULL;\r
+      }
+      internet = InternetOpen ("Wireshark Update", INTERNET_OPEN_TYPE_PRECONFIG,
+                              NULL, NULL, 0);\r
+      if(internet == NULL) {\r
+        g_warning("InternetOpen failed %u", GetLastError());\r
+        return NULL;\r
+      }
+    }
+
+  netio_ie5_conn = g_malloc(sizeof(netio_ie5_t));\r
+\r
+  netio_ie5_conn->connection = InternetOpenUrl (internet, url, NULL, 0, flags, 0);
+
+try_again:
+\r
+#if 0
+       /* XXX - implement this option */
+  if (net_user && net_passwd)
+    {
+      InternetSetOption (connection, INTERNET_OPTION_USERNAME,
+                        net_user, strlen (net_user));
+      InternetSetOption (connection, INTERNET_OPTION_PASSWORD,
+                        net_passwd, strlen (net_passwd));
+    }\r
+#endif
+\r
+#if 0
+       /* XXX - implement this option */
+  if (net_proxy_user && net_proxy_passwd)
+    {
+      InternetSetOption (connection, INTERNET_OPTION_PROXY_USERNAME,
+                        net_proxy_user, strlen (net_proxy_user));
+      InternetSetOption (connection, INTERNET_OPTION_PROXY_PASSWORD,
+                        net_proxy_passwd, strlen (net_proxy_passwd));
+    }\r
+#endif
+
+  if (resend)
+    if (!HttpSendRequest (netio_ie5_conn->connection, 0, 0, 0, 0))
+      netio_ie5_conn->connection = 0;
+
+  if (!netio_ie5_conn->connection)
+    {\r
+      switch(GetLastError ()) {\r
+      case ERROR_INTERNET_EXTENDED_ERROR:\r
+          {
+         char buf[2000];
+         DWORD e, l = sizeof (buf);
+         InternetGetLastResponseInfo (&e, buf, &l);
+         MessageBox (0, buf, "Internet Error", 0);\r
+          }\r
+          break;
+      case ERROR_INTERNET_NAME_NOT_RESOLVED:\r
+          g_warning("Internet error: The servername could not be resolved");\r
+          break;\r
+      case ERROR_INTERNET_CANNOT_CONNECT:\r
+          g_warning("Internet error: Could not connect to the server");\r
+          break;\r
+      default:\r
+          g_warning("Internet error: %u", GetLastError ());\r
+      }\r
+      return NULL;
+    }
+
+  type_s = sizeof (type);
+  InternetQueryOption (netio_ie5_conn->connection, INTERNET_OPTION_HANDLE_TYPE,
+                      &type, &type_s);
+
+  switch (type)
+    {
+    case INTERNET_HANDLE_TYPE_HTTP_REQUEST:
+    case INTERNET_HANDLE_TYPE_CONNECT_HTTP:
+      type_s = sizeof (DWORD);
+      if (HttpQueryInfo (netio_ie5_conn->connection,
+                        HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
+                        &type, &type_s, NULL))
+       {
+         if (type == 401)      /* authorization required */
+           {
+             netio_ie5_flush_io (netio_ie5_conn);\r
+              /* XXX - query net_user && net_passwd from user\r
+             get_auth (NULL);*/
+             resend = 1;
+             goto try_again;
+           }
+         else if (type == 407) /* proxy authorization required */
+           {
+             netio_ie5_flush_io (netio_ie5_conn);
+              /* XXX - query net_proxy_user && net_proxy_passwd from user\r
+             get_proxy_auth (NULL);*/
+             resend = 1;
+             goto try_again;
+           }
+         else if (type >= 300)
+           {
+              g_warning("Failed with HTTP response %u", type);\r
+              g_free(netio_ie5_conn);
+             return NULL;
+           }
+       }
+    }
+       
+       return netio_ie5_conn;
+}
+
+void
+netio_ie5_flush_io (netio_ie5_t * netio_e5_conn)
+{
+  DWORD actual = 0;
+  char buf[1024];
+  do
+    {
+      InternetReadFile (netio_e5_conn->connection, buf, 1024, &actual);
+    }
+  while (actual > 0);
+}
+
+void
+netio_ie5_disconnect (netio_ie5_t * netio_e5_conn)
+{
+  if (netio_e5_conn->connection)
+    InternetCloseHandle (netio_e5_conn->connection);\r
+  g_free(netio_e5_conn);
+}
+
+int
+netio_ie5_ok (netio_ie5_t * netio_e5_conn)
+{
+  return (netio_e5_conn->connection == NULL) ? 0 : 1;
+}
+
+int
+netio_ie5_read (netio_ie5_t * netio_e5_conn, char *buf, int nbytes)
+{
+  DWORD actual;
+  if (InternetReadFile (netio_e5_conn->connection, buf, nbytes, &actual))
+    return actual;
+  return -1;
+}
diff --git a/nio-ie5.h b/nio-ie5.h
new file mode 100644 (file)
index 0000000..d6528f3
--- /dev/null
+++ b/nio-ie5.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2000, Red Hat, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     A copy of the GNU General Public License can be found at
+ *     http://www.gnu.org/
+ *
+ * Written by DJ Delorie <dj@cygnus.com>
+ * Modified by Ulf Lamping to meet Wireshark use
+ *
+ */
+
+#ifndef SETUP_NIO_IE5_H
+#define SETUP_NIO_IE5_H
+
+/* see nio-ie5.c */
+\r
+typedef struct netio_ie5_s {\r
+    HINTERNET connection;\r
+} netio_ie5_t;\r
+
+netio_ie5_t * netio_ie5_connect (char const *url);
+void netio_ie5_disconnect (netio_ie5_t * netio_e5_conn);
+int netio_ie5_ok (netio_ie5_t * netio_e5_conn);
+int netio_ie5_read (netio_ie5_t * netio_e5_conn, char *buf, int nbytes);
+void netio_ie5_flush_io (netio_ie5_t * netio_e5_conn);
+
+#endif /* SETUP_NIO_IE5_H */
diff --git a/update.c b/update.c
new file mode 100644 (file)
index 0000000..1389e4a
--- /dev/null
+++ b/update.c
@@ -0,0 +1,343 @@
+/* update.c\r
+ *\r
+ * $Id: update.c 19935 2006-11-19 23:23:53Z gerald $\r
+ *\r
+ * Wireshark - Network traffic analyzer\r
+ * By Gerald Combs <gerald@wireshark.org>\r
+ * Copyright 1998 Gerald Combs\r
+ *\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+ */\r
+\r
+#ifdef HAVE_CONFIG_H\r
+# include "config.h"\r
+#endif\r
+\r
+#include <glib.h>\r
+#include <string.h>\r
+#include <stdio.h>\r
+\r
+#include <epan/prefs.h>\r
+#include <epan/prefs-int.h>\r
+#include <epan/filesystem.h>\r
+\r
+#include "simple_dialog.h"\r
+#include "version_info.h"\r
+\r
+#ifdef HAVE_LIBPCAP\r
+#include "capture-pcap-util.h"\r
+#endif\r
+\r
+#include "file_util.h"\r
+\r
+#include <wininet.h>\r
+#include "nio-ie5.h"\r
+\r
+\r
+/* update information about a single component */\r
+typedef struct update_info_s {\r
+    char *prefix;                   /* prefix of the update file keys */\r
+    gboolean needs_update;          /* does this component need an update */\r
+    char *version_installed;        /* the version currently installed */\r
+\r
+    char *title;                    /* the component title (name) */\r
+    char *description;              /* description of the component */\r
+    char *version_recommended;      /* the version recommended */\r
+    char *url;                      /* the URL for an update */\r
+    char *md5;                      /* md5 checksum for that update */\r
+    char *size;                     /* size of that update */\r
+} update_info_t;\r
+\r
+\r
+/* download a complete file from the internet */\r
+int\r
+download_file(const char *url, const char *filename) {\r
+    netio_ie5_t * conn;\r
+    char buf[100];\r
+    int chunk_len;\r
+    int fd;\r
+    int stream_len;\r
+    int ret = 0;\r
+\r
+\r
+    /* open output file */\r
+    fd = eth_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);\r
+    if(fd == -1) {\r
+        g_warning("Couldn't open output file %s!", filename);\r
+        return -1;\r
+    }\r
+\r
+    /* connect to url */\r
+    conn = netio_ie5_connect (url);\r
+    if (conn == NULL) {\r
+        g_warning("Couldn't connect to %s!", url);\r
+        return -1;\r
+    }\r
+\r
+    do {\r
+               /* XXX - maybe add a progress bar here */\r
+               \r
+        /* read some bytes from the url */\r
+        chunk_len = netio_ie5_read (conn, buf, sizeof(buf));\r
+\r
+        /* write bytes to the output file */\r
+        stream_len = eth_write( fd, buf, chunk_len);\r
+        if(stream_len != chunk_len) {\r
+            g_warning("output failed: stream_len %u != chunk_len %u", stream_len, chunk_len);\r
+            ret = -1;\r
+            break;\r
+        }\r
+    } while(chunk_len > 0);\r
+\r
+    netio_ie5_disconnect(conn);\r
+\r
+    eth_close(fd);\r
+\r
+    return ret;\r
+}\r
+\r
+update_info_t *\r
+update_info_new(void)\r
+{\r
+    return g_malloc0(sizeof(update_info_t));\r
+}\r
+\r
+void\r
+update_info_delete(update_info_t *update_info)\r
+{\r
+    if(update_info->prefix)\r
+        g_free(update_info->prefix);\r
+    if(update_info->version_installed)\r
+        g_free(update_info->version_installed);\r
+\r
+    if(update_info->title)\r
+        g_free(update_info->title);\r
+    if(update_info->description)\r
+        g_free(update_info->description);\r
+    if(update_info->version_recommended)\r
+        g_free(update_info->version_recommended);\r
+    if(update_info->url)\r
+        g_free(update_info->url);\r
+    if(update_info->md5)\r
+        g_free(update_info->md5);\r
+    if(update_info->size)\r
+        g_free(update_info->size);\r
+\r
+    g_free(update_info);\r
+}\r
+\r
+/* check a single key value pair */\r
+static void\r
+update_pref_check(gchar *pref_name, gchar *value, char *check_prefix, char *check_name, char **check_value)\r
+{\r
+    GString *check = g_string_new(check_prefix);\r
+    \r
+    g_string_append(check, check_name);\r
+\r
+    if(strcmp(pref_name, check->str) == 0) {\r
+        if(*check_value)\r
+            /* there shouldn't be a duplicate entry in the update file */\r
+            g_warning("Duplicate of %s: current %s former %s", pref_name, value, *check_value);\r
+        else\r
+            *check_value = g_strdup(value);\r
+    }\r
+\r
+    g_string_free(check, TRUE);\r
+}\r
+\r
+/* a new key value pair from the update file */\r
+static int\r
+update_pref(gchar *pref_name, gchar *value, void *private_data)\r
+{\r
+    update_info_t *update_info = private_data;\r
+    \r
+    update_pref_check(pref_name, value, update_info->prefix, "title",       &update_info->title);\r
+    update_pref_check(pref_name, value, update_info->prefix, "description", &update_info->description);\r
+    update_pref_check(pref_name, value, update_info->prefix, "version",     &update_info->version_recommended);\r
+    update_pref_check(pref_name, value, update_info->prefix, "update.url",  &update_info->url);\r
+    update_pref_check(pref_name, value, update_info->prefix, "update.md5",  &update_info->md5);\r
+    update_pref_check(pref_name, value, update_info->prefix, "update.size",  &update_info->size);\r
+\r
+    return PREFS_SET_OK;\r
+}\r
+\r
+/* display an update_info */\r
+static void\r
+update_info_display(update_info_t *update_info)\r
+{\r
+    GString *overview;\r
+\r
+\r
+    overview = g_string_new("");\r
+\r
+    if(update_info->title) {\r
+        g_string_append_printf(overview, "%s%s%s",\r
+            simple_dialog_primary_start(), update_info->title, simple_dialog_primary_end());\r
+    } else {\r
+        g_string_append_printf(overview, "%sComponent%s",\r
+            simple_dialog_primary_start(), simple_dialog_primary_end());\r
+    }\r
+\r
+    g_string_append(overview, "\n\n");\r
+\r
+    if(update_info->description)\r
+        g_string_append_printf(overview, "%s\n\n", update_info->description);\r
+\r
+    g_string_append_printf(overview, "Installed: %s\n", update_info->version_installed);\r
+\r
+    if(update_info->version_recommended)\r
+        g_string_append_printf(overview, "Recommended: %s\n", update_info->version_recommended);\r
+    else\r
+        g_string_append(overview, "Recommenced: unknown\n");\r
+\r
+    if(update_info->version_recommended && update_info->url)\r
+        g_string_append_printf(overview, "From: %s\n", update_info->url);\r
+\r
+    if(update_info->size)\r
+        g_string_append_printf(overview, "Size: %s", update_info->size);\r
+\r
+    simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, overview->str);\r
+\r
+    g_string_free(overview, TRUE);\r
+\r
+}\r
+\r
+/* check the version of the wireshark program */\r
+static update_info_t *\r
+update_check_wireshark(const char *local_file)\r
+{\r
+    FILE *pf;\r
+    update_info_t *update_info = update_info_new();\r
+\r
+\r
+    update_info->version_installed = g_strdup(VERSION);\r
+    update_info->prefix = "wireshark.setup.";\r
+\r
+    pf = eth_fopen(local_file, "r");\r
+    if(pf != NULL) {\r
+        /* read in update_info of Wireshark */\r
+        read_prefs_file(local_file, pf, update_pref, update_info);\r
+        fclose(pf);\r
+\r
+        /* check if Wireshark needs an update */\r
+        if(update_info->version_installed && update_info->version_recommended &&\r
+            strcmp(update_info->version_installed, update_info->version_recommended) != 0)\r
+        {\r
+            update_info->needs_update = TRUE;\r
+        }\r
+    } else {\r
+        g_warning("Could not open %s", local_file);\r
+    }\r
+\r
+    return update_info;\r
+}\r
+\r
+/* check the version of winpcap */\r
+static update_info_t *\r
+update_check_winpcap(const char *local_file)\r
+{\r
+    FILE *pf;\r
+    update_info_t * update_info = update_info_new();\r
+    GString *pcap_version_tmp;\r
+    char *pcap_version = NULL;\r
+    char *pcap_vstart;\r
+    char *pcap_vend;\r
+\r
+    \r
+    update_info->prefix = "winpcap.";\r
+\r
+    pf = eth_fopen(local_file, "r");\r
+    if(pf != NULL) {\r
+        /* read in update_info of WinPcap */\r
+        read_prefs_file(local_file, pf, update_pref, update_info);\r
+        fclose(pf);\r
+\r
+        /* get WinPcap version */\r
+        /* XXX - what's the "approved" method to get the WinPcap version? */\r
+        pcap_version_tmp = g_string_new("");\r
+        get_runtime_pcap_version(pcap_version_tmp);\r
+\r
+        /* cut out real version from "combined" version string */\r
+        pcap_vstart = strstr(pcap_version_tmp->str, "WinPcap version ");\r
+        if(pcap_vstart != NULL) {\r
+            pcap_vstart += sizeof("WinPcap version");\r
+            pcap_vend = strstr(pcap_vstart, " ");\r
+            if(pcap_vend != NULL) {\r
+                pcap_vend[0] = 0;\r
+                pcap_version = g_strdup(pcap_vstart);\r
+            }\r
+        }\r
+\r
+        update_info->version_recommended = g_strdup(pcap_version);\r
+\r
+        if(pcap_version && update_info->version_recommended &&\r
+            strcmp(pcap_version, update_info->version_recommended) != 0)\r
+        {\r
+            update_info->needs_update = TRUE;\r
+        }\r
+    } else {\r
+        g_warning("Could not open %s", local_file);\r
+    }\r
+\r
+    g_string_free(pcap_version_tmp, TRUE);\r
+    if(pcap_version)\r
+        g_free(pcap_version);\r
+\r
+    return update_info;\r
+}\r
+\r
+\r
+/* check for all updates */\r
+void\r
+update_check(void)\r
+{\r
+    char *local_file;\r
+    const char *url_file = "http://127.0.0.1/wsupdate";        /* XXX - build the URL depending on platform, versions, ... */\r
+    update_info_t *update_info;\r
+\r
+\r
+    /* build update file name */\r
+    /* XXX - using the personal path, use temp dir instead? */\r
+    local_file = get_persconffile_path("wsupdate", TRUE /*for_writing*/);\r
+    if(local_file == NULL) {\r
+        g_warning("Couldn't create output path!");\r
+        return;\r
+    }\r
+    \r
+    /* download update file */\r
+    if(download_file(url_file, local_file) == -1) {\r
+        g_warning("Couldn't download update file: %s", local_file);\r
+        g_free(local_file);\r
+        return;\r
+    }\r
+\r
+    /* check wireshark */\r
+    update_info = update_check_wireshark(local_file);\r
+    if(update_info->needs_update)\r
+        update_info_display(update_info);\r
+\r
+    update_info_delete(update_info);\r
+\r
+    /* check winpcap */\r
+    update_info = update_check_winpcap(local_file);\r
+    if(update_info->needs_update)\r
+        update_info_display(update_info);\r
+\r
+    update_info_delete(update_info);\r
+\r
+    g_free(local_file);\r
+}\r
+\r