/*
    Tucnak - VHF contest log
    Copyright (C) 2002-2015  Ladislav Vaiz <ok1zia@nagano.cz>
    and authors of web browser Links 0.96

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

*/


#include "header.h"

#include "bfu.h"
#include "kbd.h"
#include "main.h"
#include "os_dep.h"
#include "rc.h"
#include "tsdl.h"
#include "terminal.h"

#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif

#ifdef HAVE_LIBGPM
#include <gpm.h>
#endif

#if defined(HAVE_SYS_KD_H)
#include <sys/kd.h>
#endif 

#if defined(HAVE_SYS_VFS_H)
#include <sys/vfs.h>
#endif 

int is_safe_in_shell(char c)
{
    return c == '@' || c == '+' || c == '-' || c == '.' || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= 'a' && c <= 'z');
}

void check_shell_security(char **cmd)
{
    char *c = *cmd;
    while (*c) {
        if (!is_safe_in_shell(*c)) *c = '_';
        c++;
    }
}

int get_e(char *env)
{
    char *v;
    if ((v = getenv(env))) return atoi(v);
    return 0;
}

#if defined(OS2)

#define INCL_MOU
#define INCL_VIO
#define INCL_DOSPROCESS
#define INCL_DOSERRORS
#define INCL_WINCLIPBOARD
#define INCL_WINSWITCHLIST
#include <os2.h>
#include <io.h>
#include <process.h>
#include <sys/video.h>
#ifdef HAVE_SYS_FMUTEX_H
#include <sys/builtin.h>
#include <sys/fmutex.h>
#endif

#ifdef X2
/* from xf86sup - XFree86 OS/2 support driver */
#include <pty.h>
#endif

#endif

/* Terminal size */

#if defined(UNIX) 

void sigwinch(void *arg, siginfo_t *siginfo, void *ctx)
{
    ((void (*)(void))arg)();
}

void handle_terminal_resize(int fd, void (*fn)(void *))
{
#ifdef Z_HAVE_SDL    
    if (sdl) return;
#endif
    zselect_signal_set(SIGWINCH, sigwinch, fn, 0);
}

void unhandle_terminal_resize(int fd)
{
#ifdef Z_HAVE_SDL    
    if (sdl) return;
#endif
    zselect_signal_set(SIGWINCH, NULL, NULL, 0);
}

int term_get_terminal_size(int fd, int *x, int *y)
{
    struct winsize ws;
    if (!x || !y) return -1;
    if (ioctl(1, TIOCGWINSZ, &ws) != -1) {
        if (!(*x = ws.ws_col) && !(*x = get_e("COLUMNS"))) *x = 80;
        if (!(*y = ws.ws_row) && !(*y = get_e("LINES"))) *y = 24;
        return 0;
    } else {
        if (!(*x = get_e("COLUMNS"))) *x = 80;
        if (!(*y = get_e("LINES"))) *y = 24;
    }
    return 0;
}

#elif defined(WIN32)

#endif

/* Exec */

int can_twterm() /* Check if it make sense to call a twterm. */
{
    static int xt = -1;
    if (xt == -1) xt = !!getenv("TWDISPLAY");
    return xt;
}


#if defined(UNIX) || defined(WIN32)

int is_xterm()
{
    static int xt = -1;
    if (xt == -1) xt = !!getenv("DISPLAY");
    return xt;
}

#endif

int resize_count = 0;

//#if defined(UNIX) || defined(WIN32) || defined(BEOS)

#if defined(BEOS) && defined(HAVE_SETPGID)

int exe(char *path)
{
    int p;
    int s;
    if (!(p = fork())) {
        setpgid(0, 0);
        system(path);
        _exit(0);
    }
    if (p > 0) waitpid(p, &s, 0);
    else return system(path);
    return 0;
}

#else

int exe(char *path)
{
    return system(path);
}

#endif

char *get_clipboard_text()  /* !!! FIXME */
{
    char *ret = 0;
    if ((ret = (char*)g_malloc(1))!=NULL) ret[0] = 0;
    return ret;
}

void set_clipboard_text(char *data)
{
    /* !!! FIXME */
}

void set_window_title(char *title)
{
#ifdef Z_HAVE_SDL    
    if (!sdl)
#endif
    {
        if (is_xterm()){
            if (!title) title="";
            printf("\033]0;%s\007", title);
            fflush(stdout);
        }
    }
#ifdef Z_HAVE_SDL
	sdl_set_title(title);
#endif	
    /* !!! FIXME */
}

char *get_window_title()
{
    /* !!! FIXME */
    return NULL;
}

int resize_window(int x, int y)
{
    return -1;
}

//#endif

/* Threads */

#if defined(HAVE_BEGINTHREAD) || defined(HAVE_PTHREADS)

struct tdata {
    void (*fn)(void *, int);
    int h;
    char data[1];
};

void bgt(struct tdata *t)
{
    signal(SIGPIPE, SIG_IGN);
    t->fn(t->data, t->h);
    write(t->h, "x", 1);
    close(t->h);
    free(t);
}

#ifdef HAVE_PTHREADS
void *bgpt(struct tdata *t)
{
    bgt(t);
    return NULL;
}
#endif

#endif



//void block_stdin() {}
//void unblock_stdin() {}


#if defined(HAVE_BEGINTHREAD)

int start_thread(void (*fn)(void *, int), void *ptr, int l)
{
    int p[2];
    struct tdata *t;
    if (z_pipe(p) < 0) return -1;
    fcntl(p[0], F_SETFL, O_NONBLOCK);
    fcntl(p[1], F_SETFL, O_NONBLOCK);
    if (!(t = malloc(sizeof(struct tdata) + l))) return -1;
    t->fn = fn;
    t->h = p[1];
    memcpy(t->data, ptr, l);
    if (_beginthread((void (*)(void *))bgt, NULL, 65536, t) == -1) {
        close(p[0]);
        close(p[1]);
        g_free(t);
        return -1;
    }
    return p[0];
}

#ifdef HAVE_READ_KBD

int tp = -1;
int ti = -1;

void input_thread(void *p)
{
    char c[2];
    int h = (int)p;
    signal(SIGPIPE, SIG_IGN);
    while (1) {
        /*c[0] = _read_kbd(0, 1, 1);
        if (c[0]) if (write(h, c, 1) <= 0) break;
        else {
            int w;
            printf("1");fflush(stdout);
            c[1] = _read_kbd(0, 1, 1);
            printf("2");fflush(stdout);
            w = write(h, c, 2);
            printf("3");fflush(stdout);
            if (w <= 0) break;
            if (w == 1) if (write(h, c+1, 1) <= 0) break;
            printf("4");fflush(stdout);
        }*/
           /* for the records: 
                 _read_kbd(0, 1, 1) will
                 read a char, don't echo it, wait for one available and
                 accept CTRL-C.
                 Knowing that, I suggest we replace this call completly!
            */
                *c = _read_kbd(0, 1, 1);
                write(h, c, 1);
    }
    close(h);
}
#endif /* #ifdef HAVE_READ_KBD */

#if defined(HAVE_MOUOPEN) && !defined(HAVE_LIBGPM)

#define USING_OS2_MOUSE

#ifdef HAVE_SYS_FMUTEX_H
_fmutex mouse_mutex;
int mouse_mutex_init = 0;
#endif
int mouse_h = -1;

struct os2_mouse_spec {
    int p[2];
    void (*fn)(void *, char *, int);
    void *data;
    char buffer[sizeof(struct event)];
    int bufptr;
    int terminate;
};

void mouse_thread(void *p)
{
    int status;
    struct os2_mouse_spec *oms = p;
    A_DECL(HMOU, mh);
    A_DECL(MOUEVENTINFO, ms);
    A_DECL(USHORT, rd);
    A_DECL(USHORT, mask);
    struct event ev;
    signal(SIGPIPE, SIG_IGN);
    ev.ev = EV_MOUSE;
    if (MouOpen(NULL, mh)) goto ret;
    mouse_h = *mh;
    *mask = MOUSE_MOTION_WITH_BN1_DOWN | MOUSE_BN1_DOWN |
        MOUSE_MOTION_WITH_BN2_DOWN | MOUSE_BN2_DOWN |
        MOUSE_MOTION_WITH_BN3_DOWN | MOUSE_BN3_DOWN |
        MOUSE_MOTION;
    MouSetEventMask(mask, *mh);
    *rd = MOU_WAIT;
    status = -1;
    while (1) {
        int w, ww;
        if (MouReadEventQue(ms, rd, *mh)) break;
#ifdef HAVE_SYS_FMUTEX_H
        _fmutex_request(&mouse_mutex, _FMR_IGNINT);
#endif
        if (!oms->terminate) MouDrawPtr(*mh);
#ifdef HAVE_SYS_FMUTEX_H
        _fmutex_release(&mouse_mutex);
#endif
        ev.x = ms->col;
        ev.y = ms->row;
        /*debug("status: %d %d %d", ms->col, ms->row, ms->fs);*/
        dbg("mouse_thread:  ms->fs=%d\n", ms->fs);
        if (ms->fs & (MOUSE_BN1_DOWN | MOUSE_BN2_DOWN | MOUSE_BN3_DOWN)) ev.b = status = B_DOWN | (ms->fs & MOUSE_BN1_DOWN ? B_LEFT : ms->fs & MOUSE_BN2_DOWN ? B_MIDDLE : B_RIGHT);
        else if (ms->fs & (MOUSE_MOTION_WITH_BN1_DOWN | MOUSE_MOTION_WITH_BN2_DOWN | MOUSE_MOTION_WITH_BN3_DOWN)) {
            int b = ms->fs & MOUSE_MOTION_WITH_BN1_DOWN ? B_LEFT : ms->fs & MOUSE_MOTION_WITH_BN2_DOWN ? B_MIDDLE : B_RIGHT;
            if (status == -1) b |= B_DOWN;
            else b |= B_DRAG;
            ev.b = status = b;
        }
        else {
            if (status == -1) continue;
            ev.b = (status & BM_BUTT) | B_UP;
            status = -1;
        }
        if (hard_write(oms->p[1], (char *)&ev, sizeof(struct event)) != sizeof(struct event)) break;
    }
#ifdef HAVE_SYS_FMUTEX_H
    _fmutex_request(&mouse_mutex, _FMR_IGNINT);
#endif
    mouse_h = -1;
    MouClose(*mh);
#ifdef HAVE_SYS_FMUTEX_H
    _fmutex_release(&mouse_mutex);
#endif
    ret:
    close(oms->p[1]);
    /*free(oms);*/
}

void mouse_handle(struct os2_mouse_spec *oms)
{
    int r;
    if ((r = read(oms->p[0], oms->buffer + oms->bufptr, sizeof(struct event) - oms->bufptr)) <= 0) {
        unhandle_mouse(oms);
        return;
    }
    if ((oms->bufptr += r) == sizeof(struct event)) {
        oms->bufptr = 0;
        oms->fn(oms->data, oms->buffer, sizeof(struct event));
    }
}

void *handle_mouse(int cons, void (*fn)(void *, char *, int), void *data)
{
    struct os2_mouse_spec *oms;
    if (is_xterm()) return NULL;
#ifdef HAVE_SYS_FMUTEX_H
    if (!mouse_mutex_init) {
        if (_fmutex_create(&mouse_mutex, 0)) return NULL;
        mouse_mutex_init = 1;
    }
#endif
        /* This is never freed but it's allocated only once */
    if (!(oms = malloc(sizeof(struct os2_mouse_spec)))) return NULL;
    oms->fn = fn;
    oms->data = data;
    oms->bufptr = 0;
    oms->terminate = 0;
    if (z_pipe(oms->p)) {
        free(oms);
        return NULL;
    }
    _beginthread(mouse_thread, NULL, 0x10000, (void *)oms);
    zselect_set(zsel, oms->p[0], (void (*)(void *))mouse_handle, NULL, NULL, oms);
    return oms;
}

void unhandle_mouse(void *om)
{
    struct os2_mouse_spec *oms = om;
    want_draw();
    oms->terminate = 1;
    zselect_set(zsel, oms->p[0], NULL, NULL, NULL, NULL);
    close(oms->p[0]);
    done_draw();
}

void want_draw()
{
    A_DECL(NOPTRRECT, pa);
#ifdef HAVE_SYS_FMUTEX_H
    if (mouse_mutex_init) _fmutex_request(&mouse_mutex, _FMR_IGNINT);
#endif
    if (mouse_h != -1) {
        static int x = -1, y = -1;
        static int c = -1;
        if (x == -1 || y == -1 || (c != resize_count)) get_terminal_size(1, &x, &y), c = resize_count;
        pa->row = 0;
        pa->col = 0;
        pa->cRow = y - 1;
        pa->cCol = x - 1;
        MouRemovePtr(pa, mouse_h);
    }
}

void done_draw()
{
#ifdef HAVE_SYS_FMUTEX_H
    if (mouse_mutex_init) _fmutex_release(&mouse_mutex);
#endif
}

#endif /* if HAVE_MOUOPEN */

#elif defined(HAVE_CLONE)

/* This is maybe buggy... */

#include <sched.h>

struct thread_stack {
    struct thread_stack *next;
    struct thread_stack *prev;
    int pid;
    void *stack;
    void (*fn)(void *, int);
    int h;
    int l;
    char data[1];
};

void bglt(struct thread_stack *ts)
{
    ts->fn(ts->data, ts->h);
    write(ts->h, "x", 1);
    close(ts->h);
}

struct list_head thread_stacks = { &thread_stacks, &thread_stacks };

int start_thread(void (*fn)(void *, int), void *ptr, int l)
{
    struct thread_stack *ts;
    int p[2];
    int f;
    if (z_pipe(p) < 0) return -1;
    fcntl(p[0], F_SETFL, O_NONBLOCK);
    fcntl(p[1], F_SETFL, O_NONBLOCK);
    /*if (!(t = malloc(sizeof(struct tdata) + l))) return -1;
    t->fn = fn;
    t->h = p[1];
    memcpy(t->data, ptr, l);*/
    foreach(ts, thread_stacks) {
        if (ts->pid == -1 || kill(ts->pid, 0)) {
            if (ts->l >= l) goto ts_ok;
            else {
                struct thread_stack *tts = ts;
                ts = ts->prev;
                del_from_list(tts); free(tts->stack); free(tts);
            }
        }
    }
    if (!(ts = malloc(sizeof(struct thread_stack) + l))) goto fail;
    if (!(ts->stack = malloc(0x10000))) {
        free(ts);
        goto fail;
    }
    ts->l = l;
    add_to_list(thread_stacks, ts);
    ts_ok:
    ts->fn = fn;
    ts->h = p[1];
    memcpy(ts->data, ptr, l);
    if ((ts->pid = __clone((int (*)(void *))bglt, (char *)ts->stack + 0x8000, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD, ts)) == -1) {
        fail:
        close(p[0]);
        close(p[1]);
        return -1;
    }
    return p[0];
}

#elif defined(HAVE_PTHREADS)

#include <pthread.h>

int start_thread(void (*fn)(void *, int), void *ptr, int l)
{
    pthread_t thread;
    struct tdata *t;
    int p[2];
    int f;
    if (z_pipe(p) < 0) return -1;
    fcntl(p[0], F_SETFL, O_NONBLOCK);
    fcntl(p[1], F_SETFL, O_NONBLOCK);
    if (!(t = malloc(sizeof(struct tdata) + l))) return -1;
    t->fn = fn;
    t->h = p[1];
    memcpy(t->data, ptr, l);
    if (pthread_create(&thread, NULL, (void *(*)(void *))bgpt, t)) {
        close(p[0]);
        close(p[1]);
        g_free(t);
        return -1;
    }
    return p[0];
}

#else /* HAVE_BEGINTHREAD */

int start_thread(void (*fn)(void *, int), void *ptr, int l)
{
#ifdef Z_MSC_MINGW
	zinternal("start_thread unimplemented");
	return -1;
#else
    int p[2];
    int f;

    if (z_pipe(p) < 0) return -1;
    //fcntl(p[0], F_SETFL, O_NONBLOCK);
    //fcntl(p[1], F_SETFL, O_NONBLOCK);
	z_sock_nonblock(p[0], 1);
	z_sock_nonblock(p[1], 1);
    if (!(f = fork())) {
        closesocket(p[0]);
        fn(ptr, p[1]);
        z_pipe_write(p[1], "x", 1);
        z_pipe_close(p[1]);
        exit(0);
    }
    if (f == -1) {
        z_pipe_close(p[0]);
        z_pipe_close(p[1]);
        return -1;
    }
    z_pipe_close(p[1]);
    return p[0];
#endif
}

#endif

int get_output_handle() { 
#ifdef Z_HAVE_SDL    
    if (sdl)
        return -1;
    else
#endif
        return 1; 
}

int get_ctl_handle() { 
#ifdef Z_HAVE_SDL    
    if (sdl) 
        return -1;
    else
#endif
        return 0; 
}



int get_input_handle()
{
#ifdef Z_HAVE_SDL    
    if (sdl) 
        return -1;
    else
#endif
        return 0;
}


#ifdef HAVE_LIBGPM

struct gpm_mouse_spec {
    int h;
    void (*fn)(void *, char *, int);
    void *data;
};

void gpm_mouse_in(void *xxx)
{
    Gpm_Event gev;
    struct event ev;
    struct gpm_mouse_spec *gms;
        
    gms = (struct gpm_mouse_spec *)xxx;
    if (Gpm_GetEvent(&gev) <= 0) {
        zselect_set(zsel, gms->h, NULL, NULL, NULL, NULL);
        return;
    }
    ev.ev = EV_MOUSE;
    ev.x = gev.x - 1;
    ev.y = gev.y - 1;
    dbg("gpm_mouse_in: gev.buttons=%d\n", gev.buttons);
    if (gev.buttons & GPM_B_LEFT) ev.b = B_LEFT;
    else if (gev.buttons & GPM_B_MIDDLE) ev.b = B_MIDDLE;
    else if (gev.buttons & GPM_B_RIGHT) ev.b = B_RIGHT;
    else return;
    if (gev.type & GPM_DOWN) ev.b |= B_DOWN;
    else if (gev.type & GPM_UP) ev.b |= B_UP;
    else if (gev.type & GPM_DRAG) ev.b |= B_DRAG;
    else return;
    gms->fn(gms->data, (char *)&ev, sizeof(struct event));
}

void *handle_mouse(int cons, void (*fn)(void *, char *, int), void *data)
{
    int h;
    Gpm_Connect conn;
    struct gpm_mouse_spec *gms;
    conn.eventMask = ~GPM_MOVE;
    conn.defaultMask = GPM_MOVE;
    conn.minMod = 0;
    conn.maxMod = 0;
    if ((h = Gpm_Open(&conn, cons)) < 0) return NULL;
    if (!(gms = g_malloc(sizeof(struct gpm_mouse_spec)))) return NULL;
    gms->h = h;
    gms->fn = fn;
    gms->data = data;
    zselect_set(zsel, h, gpm_mouse_in, NULL, NULL, gms);
    return gms;
}

void unhandle_mouse(void *h)
{
    struct gpm_mouse_spec *gms = h;
    zselect_set(zsel, gms->h, NULL, NULL, NULL, NULL);
    Gpm_Close();
    g_free(gms);
}

#else

void *handle_mouse(int cons, void (*fn)(void *, char *, int), void *data) { return NULL; }
void unhandle_mouse(void *data) { }

#endif /* #ifdef HAVE_LIBGPM */


/*void exec_new_links(char *xterm, char *exe, char *param)
{
    char *str;
    if (!(str = g_malloc(strlen(xterm) + 1 + strlen(exe) + 1 + strlen(param) + 1))) return;
    sprintf(str, "%s %s %s", xterm, exe, param);
    exec_on_terminal(str, "", 2);
    g_free(str);
}

void open_in_new_twterm(struct terminal *term, char *exe, char *param)
{
    char *twterm;
    if (!(twterm = getenv("TUCNAK_TWTERM"))) twterm = "twterm -e";
    exec_new_links(twterm, exe, param);
}

void open_in_new_xterm(struct terminal *term, char *exe, char *param)
{
    char *xterm;
    if (!(xterm = getenv("TUCNAK_XTERM"))) xterm = "xterm -e";
    exec_new_links(xterm, exe, param);
}

void open_in_new_screen(struct terminal *term, char *exe, char *param)
{
    exec_new_links("screen", exe, param);
}

#ifdef OS2
void open_in_new_vio(struct terminal *term, char *exe, char *param)
{
    exec_new_links("cmd /c start /c /f /win", exe, param);
}

void open_in_new_fullscreen(struct terminal *term, char *exe, char *param)
{
    exec_new_links("cmd /c start /c /f /fs", exe, param);
}
#endif

#ifdef BEOS
void open_in_new_be(struct terminal *term, char *exe, char *param)
{
    exec_new_links("Terminal", exe, param);
}
#endif
  
struct {
    int env;
    void (*fn)(struct terminal *term, char *, char *);
    char *text;
    char *hk;
} oinw[] = {
    {ENV_XWIN, open_in_new_xterm, CTEXT(T_XTERM), CTEXT(T_HK_XTERM)},
    {ENV_TWIN, open_in_new_twterm, CTEXT(T_TWTERM), CTEXT(T_HK_TWTERM)},
    {ENV_SCREEN, open_in_new_screen, CTEXT(T_SCREEN), CTEXT(T_HK_SCREEN)},
#ifdef OS2
    {ENV_OS2VIO, open_in_new_vio, CTEXT(T_WINDOW), CTEXT(T_HK_WINDOW)},
    {ENV_OS2VIO, open_in_new_fullscreen, CTEXT(T_FULL_SCREEN), CTEXT(T_HK_FULL_SCREEN)},
#endif
#ifdef BEOS
    {ENV_BE, open_in_new_be, CTEXT(T_BEOS_TERMINAL), CTEXT(T_HK_BEOS_TERMINAL)},
#endif
    {0, NULL, NULL}
};

  */





#if 0
#ifndef HAVE_LOCKF
#ifdef Z_MSC_MINGW
// TODO
#else
/* lockf is a simplified interface to fcntl's locking facilities.  */
/* thanx to glibc */
int
lockf (int fd, int cmd, off_t len)
{
  struct flock fl;

  memset ((char *) &fl, '\0', sizeof (fl));

  /* lockf is always relative to the current file position.  */
  fl.l_whence = SEEK_CUR;
  fl.l_start = 0;
  fl.l_len = len;

  switch (cmd)
    {
    case F_TEST:
      /* Test the lock: return 0 if FD is unlocked or locked by this process;
     return -1, set errno to EACCES, if another process holds the lock.  */
      if (fcntl (fd, F_GETLK, &fl) < 0)
    return -1;
      if (fl.l_type == F_UNLCK || fl.l_pid == getpid ())
    return 0;
      errno=EACCES;
      return -1;

    case F_ULOCK:
      fl.l_type = F_UNLCK;
      cmd = F_SETLK;
      break;
    case F_LOCK:
      fl.l_type = F_WRLCK;
      cmd = F_SETLKW;
      break;
    case F_TLOCK:
      fl.l_type = F_WRLCK;
      cmd = F_SETLK;
      break;

    default:
      errno=EINVAL;
      return -1;
    }

  return fcntl (fd, cmd, &fl);
}
#endif
#endif
#endif


int save_screen(){
    if (!is_xterm()) return 1;
    
    printf("\033[?1049h");
    fflush(stdout);
    return 0;
}

int restore_screen(){
    if (!is_xterm()) return 1;
    
    printf("\033[?1049l");
    fflush(stdout);
    return 0;
}

#define MTAB_DELIM " \t"
gchar * get_mp(gchar *device){
    FILE *f;
    char *filename,*s,*token_ptr;
    GString *gs;
    gchar *dev,*mp,*ret;

    f=fopen(filename="/proc/mounts","r");
    if (!f) f=fopen(filename="/etc/mtab", "r");
    if (!f) return 0;

    ret=NULL;
    gs=g_string_sized_new(100);
    while ((s=zfile_fgets(gs,f,1))!=NULL){
        dev=strtok_r(s,MTAB_DELIM,&token_ptr);
        mp=strtok_r(NULL, MTAB_DELIM, &token_ptr);
        if (!dev || !mp) continue;
        if (strcmp(dev,device)==0){
            ret=g_strdup(mp);
            break;
        }
    }
    g_string_free(gs, TRUE);
    fclose(f);
    return ret;
}

int floppy_is_mounted(gchar *floppydev, gchar *path_to_floppy){
    gchar *mp;
    int ret;

    mp=get_mp(floppydev);
    if (!mp) return 0;

    ret=!strcmp(mp,path_to_floppy);
    g_free(mp);
    return ret;
}

#ifdef UNIX
int is_in_mtab(gchar *mountpoint){
    FILE *f;
    char *filename,*s,*token_ptr;
    GString *gs;
    gchar *dev,*mp;
    int ret;

	/*dbg("mountpoint ='%s'\n", mountpoint);*/
    f=fopen(filename="/proc/mounts","r");
    if (!f) f=fopen(filename="/etc/mtab", "r");
    if (!f) return 0;

    ret=0;
    gs=g_string_sized_new(100);
    while ((s=zfile_fgets(gs,f,1))!=NULL){
        dev=strtok_r(s,MTAB_DELIM,&token_ptr);
        mp=strtok_r(NULL, MTAB_DELIM, &token_ptr);
        if (!dev || !mp) continue;
        if (strcmp(mp,mountpoint)==0){
            ret=1;
            break;
        }
    }
    g_string_free(gs, TRUE);
    fclose(f);
	/*dbg("return %d\n", ret);*/
    return ret;
}
#else
int is_in_mtab(gchar *mountpoint){
	if (z_df(mountpoint) > 0.0) return 1;
	return 0;
}
#endif



static int sound_fd=-1;
int sound_pid=-1;

int init_sound(){

#ifdef Z_UNIX
    int ret,i;
    int fds[2];

	progress(VTEXT(T_INIT_SPEAKER));		
    if (pipe(fds)) zinternal("Can't create pipe");
    /*dbg("sound pipe %d->%d\n", fds[1], fds[0]);*/

    ret=fork();
    if (ret<0){
        zinternal("Can't fork");
    }
    if (ret) {  /* parent */
        dbg("sound_pid = %d\n", ret);
        sound_pid = ret;
        closesocket(fds[0]);
        sound_fd=fds[1];
        return 0; 
    }
    /* child */
    sleep(1);
    closesocket(fds[1]);
    close(0);
    dup2(fds[0], 0);
    closesocket(fds[0]);
    for (i=3;i<1024;i++) close(i);
    execlp("soundwrapper", "soundwrappes", "-q", NULL);
	exit(-1);
#else
	return 0;
#endif
}

int free_sound(){
#ifdef Z_UNIX
    int cmd, ret;
    
    if (sound_fd<0) return -1;
	progress(VTEXT(T_FREE_SPEAKER));		

    cmd=-1;
    ret=write(sound_fd, &cmd, sizeof(int));
    if (ret!=sizeof(int)){
        char errstr[1030];
        dbg("error writing sound_fd=%d (error %d) '%s'\n", sound_fd, errno, strerror_r(errno, errstr, sizeof(errstr)));      
    }
    close(sound_fd);
    sound_fd=-1;
#endif
    return 0;
}

int abort_sound(){
    if (sound_fd<0) return -1;
    z_pipe_close(sound_fd);
    sound_fd=-1;
    return 0;
}

int sound(int freq){
#ifdef Z_UNIX
    int ret;

    if (sound_fd<0) {
/*        dbg("sound_fd is closed\n");*/
        return -1;
    }
    
    ret=z_pipe_write(sound_fd, &freq, sizeof(int));
    if (ret!=sizeof(int)){
        char errstr[1030];

        
        dbg("error writing sound_fd=%d (error %d) '%s'\n", sound_fd, errno, strerror_r(errno, errstr, sizeof(errstr)));      
        z_pipe_close(sound_fd);
        sound_fd=-1;
        return -1;
    }
#endif
    return 0;
}

