Logo Search packages:      
Sourcecode: gretl version File versions  Download package

update_client.c

/* auto updater program for gretl on win32:
   gtk2 version, Allin Cottrell, October 2003 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#ifdef WIN32
# include <windows.h>
# include <winsock.h>
#endif

#ifdef USE_GTK
# include <gtk/gtk.h>
#endif

#include "updater.h"
#include "webget.h"

FILE *flg;
int logit;
int debug;

#define MAXLEN 512

enum {
    UPDATER_DEFAULT,
    UPDATER_GET_LISTING,
    UPDATER_GET_FILE
} program_opts;

static char errbuf[256];
static char get_fname[48];
static int ask_before_download = 1;
static time_t filedate;
static int argcount;
static int prog_opt;

#ifdef USE_GTK
static GtkWidget *mainwin;
static GtkWidget *mainlabel;
static char infobuf[256];
static void put_text_on_window (void);
#else
# define GTK_RESPONSE_ACCEPT IDYES
# define GTK_RESPONSE_NO     IDNO
#endif

static void getout (int err)
{
    if (logit) {
      fprintf(flg, "Exiting with err = %d\n", err);
      fclose(flg);
      logit = 0;
    }

    if (*get_fname && prog_opt != UPDATER_GET_FILE) {
      remove(get_fname);
    }

    if (err) {
      exit(EXIT_FAILURE);
    } 
}

#ifdef WIN32 /* Windows-specific code */

enum {
    GRETL_NOT_RUNNING = 0,
    GRETL_RUNNING,
    GRETL_RUN_UNKNOWN
};

static int gretl_run_status;

static int win_error (void)
{
    LPVOID msg;
    DWORD dw = GetLastError(); 

    if (dw == 0) return 0;

    fprintf(stderr, "GetLastError() returned %u\n", (unsigned) dw);

    if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
                  FORMAT_MESSAGE_FROM_SYSTEM | 
                  FORMAT_MESSAGE_IGNORE_INSERTS,
                  NULL,
                  dw,
                  0, 
                  (LPTSTR) &msg,
                  0,
                  NULL)) {
      MessageBox(NULL, (LPCTSTR) msg, "Error", MB_OK | MB_ICONINFORMATION);
      LocalFree(msg);
    }

    return dw;
}

static int create_child_process (char *prog) 
{ 
    PROCESS_INFORMATION proc_info; 
    STARTUPINFO start_info; 
    int ret;
 
    ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION));
    ZeroMemory(&start_info, sizeof(STARTUPINFO));
    start_info.cb = sizeof(STARTUPINFO); 
 
    ret = CreateProcess(NULL, 
                        prog,          /* command line */
                        NULL,          /* process security attributes  */
                        NULL,          /* primary thread security attributes */ 
                        TRUE,          /* handles are inherited  */
                        0,             /* creation flags  */
                        NULL,          /* NULL = use parent's environment  */
                        NULL,          /* use parent's current directory  */
                        &start_info,   /* STARTUPINFO pointer */ 
                        &proc_info);   /* receives PROCESS_INFORMATION  */

    if (ret == 0) {
        win_error();
    }

    return ret;
}

static int yes_no_dialog (const char *msg)
{
    int ret;

    ret = MessageBox(NULL, msg, "gretl updater", 
                 MB_YESNO | MB_ICONQUESTION);

    if (ret == IDYES) {
      return GTK_RESPONSE_ACCEPT;
    } else {
      return GTK_RESPONSE_NO;
    }
}

static int msgbox (const char *msg, int err)
{
    int ret;

    if (err) {
        ret = MessageBox(NULL, msg, "gretl updater", MB_OK | MB_ICONERROR);
    } else {
        ret = MessageBox(NULL, msg, "gretl updater", MB_OK | MB_ICONINFORMATION);
    }

    return ret;
}

static void ws_cleanup (void)
{
    WSACleanup();
}

static int ws_startup (void)
{
    WORD requested;
    WSADATA data;

    requested = MAKEWORD(1, 1);

    if (WSAStartup(requested, &data)) {
        errbox("Couldn't find usable socket driver");
        return 1;
    }

    if (LOBYTE (requested) < 1 || (LOBYTE (requested) == 1 &&
                                   HIBYTE (requested) < 1)) {
        errbox("Couldn't find usable socket driver");
        WSACleanup();
        return 1;
    }
    atexit(ws_cleanup);
    return 0;
}

BOOL CALLBACK record_gretl_running (HWND hw, LPARAM lp)
{
    if (gretl_run_status == GRETL_RUNNING) {
      return TRUE;
    } else if (hw == NULL) {
      return FALSE;
    } else {
      char wtitle[128];
      int len;

      len = GetWindowText(hw, wtitle, sizeof wtitle);
      if (len > 0 && !strncmp(wtitle, "gretlw32", 7)) {
          gretl_run_status = GRETL_RUNNING;
      }
      return TRUE;
    } 
}

static int check_for_gretl (void)
{
    int ok = EnumWindows(record_gretl_running, 0);

    if (!ok) {
      gretl_run_status = GRETL_RUN_UNKNOWN;
    }

    return gretl_run_status;
}

#else /* ! WIN32 */

gint yes_no_dialog (char *msg)
{
    GtkWidget *dialog, *label, *hbox;
    int ret;

    dialog = gtk_dialog_new_with_buttons ("gretl updater",
                                NULL,
                                GTK_DIALOG_MODAL | 
                                GTK_DIALOG_DESTROY_WITH_PARENT,
                                GTK_STOCK_YES,
                                GTK_RESPONSE_ACCEPT,
                                GTK_STOCK_NO,
                                GTK_RESPONSE_NO,
                                NULL);
    
    label = gtk_label_new (msg);
    gtk_widget_show(label);
    hbox = gtk_hbox_new(FALSE, 0);
    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10);
    gtk_widget_show(hbox);
    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
                   hbox, FALSE, FALSE, 10);

    ret = gtk_dialog_run(GTK_DIALOG(dialog));
                                
    gtk_widget_destroy(dialog);

    switch (ret) {
    case GTK_RESPONSE_ACCEPT: 
      return ret;
    default: 
      return GTK_RESPONSE_NO;
    }
}

static int msgbox (const char *msg, int err)
{
    GtkWidget *dialog;

    dialog = gtk_message_dialog_new (NULL, 
                             GTK_DIALOG_DESTROY_WITH_PARENT,
                             (err)? GTK_MESSAGE_ERROR : GTK_MESSAGE_INFO,
                             GTK_BUTTONS_CLOSE,
                             msg);
    gtk_dialog_run (GTK_DIALOG (dialog));
    gtk_widget_destroy (dialog);
    
    return 0;
}

#endif /* WIN32 vs ! WIN32 */

static char *get_size_string (size_t fsize)
{
    static char sizestr[32] = "";

    if (fsize > 1024 * 1024) {
      sprintf(sizestr, " (%.2f MB)", (double) fsize / (1024. * 1024.));
    } else if (fsize >= 10 * 1024) {
      sprintf(sizestr, " (%.1f KB)", (double) fsize / 1024.);
    } else {
      sprintf(sizestr, " (%u bytes)", fsize);
    }

    return sizestr;
}

#ifdef USE_GTK

static void put_text_on_window (void)
{
    gtk_label_set_text(GTK_LABEL(mainlabel), infobuf);
}

#endif

int errbox (const char *msg) 
{
    return msgbox(msg, 1);
}

int infobox (const char *msg) 
{
    return msgbox(msg, 0);
}

void listerr (char *buf, char *fname)
{
    char mybuf[256];

    *mybuf = '\0';

    if (fname != NULL && *fname) {
      sprintf(mybuf, "Error retrieving '%s'", fname);
      if (logit) {
          fprintf(flg, "Error retrieving '%s'\n", fname);
      }
    } else {
      sprintf(mybuf, "Error retrieving file listing");
      if (logit) {
          fputs("Error retrieving file listing\n", flg);
      }
    }

    if (*buf != '\0') {
      strcat(mybuf, "\n");
      strcat(mybuf, buf);
    }

    errbox(mybuf);
}

void usage (char *prog)
{
    char usebuf[1024];

    sprintf(usebuf, "examples of usage:\n"
         "%s (automatically get any new files)\n"
         "%s -f foo.tgz (get foo.tgz, output to file)\n"
         "%s -l (list new files on server)",
         prog, prog, prog);
    infobox(usebuf);
    getout(0);
}

time_t get_time_from_stamp_file (const char *fname)
     /* E.g. Sun Mar 16 13:50:52 EST 2003 */
{
    FILE *fp;
    struct tm stime;
    char wday[4], mon[4];
    int i;
    const char *months[] = {
      "Jan", "Feb", "Mar",
      "Apr", "May", "Jun",
      "Jul", "Aug", "Sep",
      "Oct", "Nov", "Dec"
    };

    fp = fopen(fname, "r");
    if (fp == NULL) {
      if (logit) {
          fprintf(flg, "Couldn't open %s\n", fname);
      }
      return (time_t) 0;
    }

    if (fscanf(fp, "%3s %3s %d %d:%d:%d %*s %d", 
             wday, mon, &stime.tm_mday, &stime.tm_hour,
             &stime.tm_min, &stime.tm_sec, &stime.tm_year) != 7) {
      fclose(fp);
      if (logit) {
          fprintf(flg, "Didn't get a valid date from %s\n", fname);
      }
      return (time_t) 0;
    }

    fclose(fp);
    
    stime.tm_mon = 20;
    for (i=0; i<12; i++) {
      if (!strcmp(mon, months[i])) {
          stime.tm_mon = i;
          break;
      }
    }

    if (stime.tm_mon == 20) {
      if (logit) {
          fprintf(flg, "Didn't get a valid month from %s\n", fname);
      }
      return (time_t) 0;
    }

    stime.tm_year -= 1900;

    return mktime(&stime);
}

static int real_program (void)
{
    int i, err = 0, tarerr = 0, remerr = 0;
    int unpack_ok = 0;
    char *getbuf = NULL;
    char *line;
    size_t fsize;

    if (argcount == 1) {
      /* no arguments: a default update */

#ifdef USE_GTK
      strcpy(infobuf, "Looking for gretl updates...");
      put_text_on_window();
#endif

      if (logit) {
          fputs("doing default update (argcount = 1)\n", flg);
      }

      getbuf = mymalloc(GRETL_BUFSIZE);
      if (getbuf == NULL) return 1;

      clear(getbuf, GRETL_BUFSIZE);

      if (logit) {
          fputs("getbuf allocated OK\n", flg);
      }

      err = files_query(&getbuf, errbuf, filedate);
      if (err) {
         listerr(errbuf, NULL);
         getout(1);
      }

      if (logit) fputs("call to files_query: success\n", flg);

      i = 0;
      while ((line = strtok((i)? NULL: getbuf, "\n"))) {
          *get_fname = '\0';
          fsize = (size_t) 0;

          if (logit) {
            fprintf(flg, "working on line %d of getbuf\n = '%s'\n", 
                  i, line);
          }

          i++;
          sscanf(line, "%s %u", get_fname, &fsize);

          if (!strcmp(get_fname, "No")) {
            infobox("There are no new files on the server");
            if (logit) {
                fputs("no new files on server\n", flg);
            }
            break;
          } else if (ask_before_download) {
            int resp;
            char query[128];

            sprintf(query, "An update file is available%s.\n"
                  "Get it now?", get_size_string(fsize));
            resp = yes_no_dialog(query);
            if (resp != GTK_RESPONSE_ACCEPT) break;
          }

#ifdef USE_GTK
          sprintf(infobuf, "Downloading %s", get_fname);
          put_text_on_window();    
          while (gtk_events_pending()) gtk_main_iteration();
#endif
          
          if (logit) {
            fprintf(flg, "trying to get '%s'\n", get_fname);
          }

          err = get_remote_file(get_fname, errbuf);

          if (logit) {
            fprintf(flg, "get_remote_file() returned %d\n", err);
          }     
          if (err) {
            listerr(errbuf, get_fname);
            return 1;
          }

          if (logit) fprintf(flg, "Doing untgz on %s...\n", get_fname);
          if (logit && debug) {
            fputs("[debug: faking it]\n", flg);
          } else {
            tarerr = untgz(get_fname);
          }

          if (logit) fprintf(flg, "Removing %s... ", get_fname);
          remerr = remove(get_fname);

          if (logit) fprintf(flg, "%s\n", (remerr)? "failed" : "succeeded");
          if (!err && !tarerr && !remerr) {
            unpack_ok = 1;
          } else {
            err = 1;
          }
      }
    }

    else if (prog_opt == UPDATER_GET_LISTING) { /* get listing */
      getbuf = malloc(8192); 
      clear(getbuf, 8192);
      err = files_query(&getbuf, errbuf, filedate);
      if (err) {
          listerr(errbuf, NULL);
          free(getbuf);
          getout(1);
      }
      if (getbuf) {
          infobox(getbuf);
      }
      free(getbuf);
    }
    
    else if (prog_opt == UPDATER_GET_FILE) { /* get a specified file */
      err = get_remote_file(get_fname, errbuf);
      if (err) {
          listerr(errbuf, get_fname);
          getout(1);
      }
      tarerr = untgz(get_fname);
      remerr = remove(get_fname);
      if (!err && !tarerr && !remerr) unpack_ok = 1;
    }

#ifdef WIN32
    if (unpack_ok) {
      int resp;

      resp = yes_no_dialog("gretl update succeeded.\r\nStart gretl now?");
      if (resp == GTK_RESPONSE_ACCEPT) {
          create_child_process("gretlw32.exe");
      }
    }
#else
    if (unpack_ok) {
      infobox("gretl update succeeded");
    }
#endif

    getout(err);

#ifdef USE_GTK
    gtk_main_quit();
#endif

    return TRUE;
}

#ifdef USE_GTK

static gint cancel_callback (void)
{
    gtk_main_quit();
    return FALSE;
}

static void create_main_gtk_window (int warn)
{
    GtkWidget *main_vbox;
    GtkWidget *buttonbox;
    GtkWidget *tmp;
    int mainwin_width = 300;
    int mainwin_height = 100;

    mainwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(mainwin), "gretl updater");
    gtk_window_set_default_size(GTK_WINDOW(mainwin), 
                        mainwin_width, mainwin_height);
    
    main_vbox = gtk_vbox_new(FALSE, 4);
    gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 8);
    gtk_container_add(GTK_CONTAINER(mainwin), main_vbox);

    if (warn) {
      mainlabel = gtk_label_new("If gretl is running, please close it "
                          "down before running the updater.\n\n"
                          "Press OK to proceed or Cancel to quit");
    } else {
      mainlabel = gtk_label_new("Press OK to proceed or Cancel to quit");
    }
      
    gtk_box_pack_start(GTK_BOX(main_vbox), mainlabel, TRUE, TRUE, 0);

    buttonbox = gtk_hbox_new(TRUE, 4);
    gtk_container_set_border_width(GTK_CONTAINER(buttonbox), 8);
    gtk_box_pack_start(GTK_BOX(main_vbox), buttonbox, FALSE, FALSE, 0);

    /* Create an "OK" button */
    tmp = gtk_button_new_from_stock(GTK_STOCK_OK);
    GTK_WIDGET_SET_FLAGS(tmp, GTK_CAN_DEFAULT);
    gtk_container_add(GTK_CONTAINER(buttonbox), tmp);
    g_signal_connect (G_OBJECT(tmp), "clicked", 
                  G_CALLBACK(real_program), NULL);
    gtk_widget_grab_default (tmp);

    /* Create a "Cancel" button */
    tmp = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
    gtk_container_add(GTK_CONTAINER(buttonbox), tmp);
    g_signal_connect (G_OBJECT(tmp), "clicked", 
                  G_CALLBACK(cancel_callback), NULL);
    
    gtk_widget_show_all(mainwin);
}

#else 

static void win32_start (int warn)
{
    LPCTSTR msg;
    int resp;

    if (warn) {
      msg = "If gretl is running, please close it "
          "down before running the updater.\n\n"
          "Press OK to proceed or Cancel to quit";
    } else {
      msg = "Press OK to proceed or Cancel to quit";
    }

    resp = MessageBox(GetActiveWindow(), msg, "gretl updater", MB_OKCANCEL);

    if (resp == IDOK) {
      real_program();
    }
}

int show_progress (long res, long expected, int flag)
{
    return 0;
}

#endif

#ifdef WIN32
int main (int argc, char *argv[])
#else
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                LPSTR CmdLine, int Show)
#endif
{
    const char *testfile = "gretl.stamp";
    int warn = 1;
#ifdef WIN32
    char gretldir[MAXLEN];
#endif

    prog_opt = UPDATER_DEFAULT;
    *get_fname = '\0';

    argcount = argc;

    if (argcount == 2 && !strcmp(argv[1], "-d")) {
      argcount--;
      debug = 1;
    }

    if (argcount == 2 && !strcmp(argv[1], "-g")) {
      /* flag for updater spawned by gretl: no need to repeat
         the question whether the user wants to download */
      argcount--;
      ask_before_download = 0;
      warn = 0;
    }

    if (argcount == 2 && !strcmp(argv[1], "-l")) {
      prog_opt = UPDATER_GET_LISTING;
    }

    if (argcount == 3 && !strcmp(argv[1], "-f")) {
      prog_opt = UPDATER_GET_FILE;
      strncpy(get_fname, argv[2], 47);
    }

    if (argcount > 1 && strcmp(argv[1], "-f") == 0 && argc != 3) {
      usage(argv[0]);
    }    

#ifdef WIN32
    if (read_reg_val(HKEY_CLASSES_ROOT, "gretldir", gretldir)) {
      errbox("Couldn't get the path to the gretl installation\n"
             "from the Windows registry");
      exit(EXIT_FAILURE);
    }

    if (!SetCurrentDirectory(gretldir)) {
      errbox("Couldn't move to the gretl folder");
      exit(EXIT_FAILURE);
    }

    if (warn) {
      check_for_gretl();
      if (gretl_run_status == GRETL_RUNNING) {
          errbox("Please close gretl before running the updater");
          exit(EXIT_FAILURE);
      } else if (gretl_run_status == GRETL_NOT_RUNNING) {
          warn = 0;
      }
    }

    if (ws_startup()) exit(EXIT_FAILURE);
#endif

    flg = fopen("updater.log", "w");
    if (flg == NULL) {
      logit = 0;
    } else {
      time_t now = time(NULL);

      setvbuf(flg, NULL, _IOLBF, 0);
      fprintf(flg, "gretl updater running %s", ctime(&now));
      logit = 1;
    } 

    filedate = get_time_from_stamp_file(testfile);

    if (filedate == (time_t) 0) {
      sprintf(errbuf, "Couldn't get time-stamp from file '%s'", testfile);
      errbox(errbuf);
      getout(1);
    } 

#ifdef USE_GTK
    gtk_init(&argc, &argv);
    create_main_gtk_window(warn);
    gtk_main();
#else
    win32_start(warn);
#endif

    getout(0);

    return 0;
}

Generated by  Doxygen 1.6.0   Back to index