gcc -Wall -g -o lv3_example -pthread example.c -lventrilo3
/*
 * vim: softtabstop=4 shiftwidth=4 cindent foldmethod=marker expandtab
 *
 * Copyright 2009-2010 Eric Kilfoil 
 *
 * This file is part of Mangler.
 *
 * Mangler 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 3 of the License, or
 * (at your option) any later version.
 *
 * Mangler is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Mangler.  If not, see <http://www.gnu.org/licenses/>.
 */

#define _GNU_SOURCE


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <strings.h>
#include <sys/types.h>
#include <string.h>
#include <getopt.h>
#include <pthread.h>
#include <ventrilo3.h>

void usage(char *argv[]);
void ctrl_c(int signum);
void *jukebox_connection(void *connptr);
void *jukebox_player(void *connptr);

int debug = 0;
int should_exit = 0;

struct _conninfo {
    char *server;
    char *username;
    char *password;
    char *channelid;
    char *path;
};

void ctrl_c (int signum) {
    printf("disconnecting... ");
    v3_logout();
    printf("done\n");
    exit(0);
}

void usage(char *argv[]) {
    fprintf(stderr, "usage: %s -s hostname:port -u username -c channelid /path/to/music\n", argv[0]);
    exit(1);
}

void *jukebox_connection(void *connptr) {
    struct _conninfo *conninfo;
    _v3_net_message *msg;
    conninfo = connptr;
    if (debug >= 2) {
        v3_debuglevel(V3_DEBUG_ALL);
    }
    if (! v3_login(conninfo->server, conninfo->username, conninfo->password, "")) {
        fprintf(stderr, "could not log in to server: %s\n", _v3_error(NULL));
    }
    while ((msg = _v3_recv(V3_BLOCK)) != NULL) {
        switch (_v3_process_message(msg)) {
            case V3_MALFORMED:
                _v3_debug(V3_DEBUG_INFO, "received malformed packet");
                break;
            case V3_NOTIMPL:
                _v3_debug(V3_DEBUG_INFO, "packet type not implemented");
                break;
            case V3_OK:
                _v3_debug(V3_DEBUG_INFO, "packet processed");
                break;
        }
    }
    should_exit = 1;
    pthread_exit(NULL);
}

void *jukebox_player(void *connptr) {
    struct _conninfo *conninfo;
    v3_event *ev;

    conninfo = connptr;
    while ((ev = v3_get_event(V3_BLOCK))) {
        if (debug) {
            fprintf(stderr, "jukebox: got event type %d\n", ev->type);
        }
        switch (ev->type) {
            case V3_EVENT_DISCONNECT:
                should_exit = 1;
                free(ev);
                pthread_exit(NULL);
                break;
            case V3_EVENT_LOGIN_COMPLETE:
                v3_change_channel(atoi(conninfo->channelid), "");
                v3_join_chat();
                break;
        }
        free(ev);
    }
    pthread_exit(NULL);
}

int main(int argc, char *argv[]) {
    int opt;
    int rc;
    pthread_t network;
    pthread_t player;
    struct _conninfo conninfo;

    while ((opt = getopt(argc, argv, "dh:p:u:c:")) != -1) {
        switch (opt) {
            case 'd':
                debug++;
                break;
            case 'h':
                conninfo.server = strdup(optarg);
                break;
            case 'u':
                conninfo.username = strdup(optarg);
                break;
            case 'c':
                conninfo.channelid = strdup(optarg);
                break;
            case 'p':
                conninfo.password = strdup(optarg);
                break;
        }
    }
    if (! conninfo.server)  {
        fprintf(stderr, "error: server hostname (-h) was not specified\n");
        usage(argv);
    }
    if (! conninfo.username)  {
        fprintf(stderr, "error: username (-u) was not specified\n");
        usage(argv);
    }
    if (! conninfo.channelid) {
        fprintf(stderr, "error: channel id (-c) was not specified\n");
        usage(argv);
    }
    if (! conninfo.password) {
        conninfo.password = "";
    }
    if (optind >= argc) {
        fprintf(stderr, "error: path to music library not specified\n");
        usage(argv);
    }
    conninfo.path = strdup(argv[argc-1]);
    fprintf(stderr, "server: %s\nusername: %s\nmedia path: %s\n", conninfo.server, conninfo.username, conninfo.path);
    rc = pthread_create(&network, NULL, jukebox_connection, (void *)&conninfo);
    rc = pthread_create(&player, NULL, jukebox_player, (void *)&conninfo);
    signal (SIGINT, ctrl_c);
    while (! should_exit) {
        sleep(1);
    }
    return(0);
}