Logo Search packages:      
Sourcecode: icecast-client version File versions  Download package

shout.c

 /* shout @ ice v 0.5.0
 * Sep 1, 1999 schism@icecast.org
 *
 * shouting client v 0.4.2
 * 980609 eel@musiknet.se
 * Desc:
 * Connects to hostname on port 8000, then tries to send the
 * audiostream at the specified bitrate. yet does so much more.
 * This is no longer quickhack <tm>
 * Credits:
 * This program uses code directly stolen from rand.c.
 * Rand.c was written by Erik Greenwald <br0ke@math.smsu.edu>
 * Mpeg.c is a C++->C port from <slicer@bimbo.hive.no>'s mp3info package.
 * -
 * 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, or (at your option)
 * any later version.
 * 
 * This program 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 this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifndef __EXTENSIONS__
#define __EXTENSIONS__
#endif
#ifndef __USE_BSD
#define __USE_BSD
#endif
#ifndef __USE_GNU
#define __USE_GNU
#endif

#ifndef __USE_SVID
#define __USE_SVID
#endif

#include <sys/types.h>
#include <time.h>
#include <stdlib.h>

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
/* #include <winsock2.h> */
#include <winsock.h>
#include <mmsystem.h>
#include <fcntl.h>
#include <io.h>
#include <direct.h>
#include <process.h>
#include <winbase.h>
#else /*  *NIX  */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <stdarg.h>
#include <signal.h>
#include <ctype.h>
#include <stdarg.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/time.h>
#endif /* !win32 */

#ifndef __USE_SVID
#define __USE_SVID
#endif

#ifndef __USE_BSD
#define __USE_BSD
#endif

#include <string.h>
#include <stdio.h>
#include <sys/stat.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include "shout.h"
#include "sock.h"
#include "util.h"

#ifndef O_BINARY
#define O_BINARY 0x0
#endif

#define FDELIM ';'            /* playlist could have path c:\ect..., can't use colons */

extern int errno;

#ifdef _WIN32                 /* no microsec */
const int multfactor = 1000;

#else
#ifdef HAVE_LONG_LONG
const int multfactor = 1;

#else
const int multfactor = 1000;

#endif
#endif /* WIN32 */

/* Main server socket */
sock_t s;

/* Playlist indicator */
int current_song;

/* Valid Playlist indicator */
int valid_song_found;

/* ^C is pressed? */
int intflag;

#ifndef _WIN32
struct timeval lastint, shoutstart;

#endif

/* Settings and whatnot */
set_t set;

#if _WIN32
WSADATA wsaData;

#endif

void find_config_file (int argc, char **argv);

#ifdef _WIN32
BOOL WINAPI px_shutdown_evt (DWORD CtrlType);
#endif /* win32 */

int
main (int argc, char **argv)
{
      int len=0;
      int ret=0;
      char *path;

      /*   char buf[BUFSIZE];   */
      struct hostent *hp;
      struct sockaddr_in name;

#ifdef _WIN32
      unsigned int addr;

#endif /* win32 */

      umask (022);
      current_song = 0;
      intflag = 0;

      scream (NORMAL, "%s - www.icecast.org\n\n", VERSION);

#ifdef _WIN32
      timeBeginPeriod (1);
      if (!SetConsoleCtrlHandler( px_shutdown_evt, 1 ))
            scream (TOERROR, "FAILED setting up win32 signal handler\n");

      ret = SetPriorityClass (GetCurrentProcess (), HIGH_PRIORITY_CLASS);
    if (!ret)
      scream (NORMAL, "FAILED setting: Win32 Process Class to [%s]\n", desc_priorityclass (GetPriorityClass (GetCurrentProcess ())));
    else
      scream (VERBOSE, "(win32 process class [%s])\n", desc_priorityclass (GetPriorityClass (GetCurrentProcess ())));
#else
      gettimeofday (&lastint, NULL);
      gettimeofday (&shoutstart, NULL);
#endif

      setup_defaults ();


      find_config_file(argc, argv);
      path = strdup(set.etcdir);
      ret = parse_config_file (path, set.configfile);

      if (!parse_arguments(argc, argv) && (ret <= 0)) {
        scream (TOERROR, "no server info to startup\n");
            usage();
            px_shutdown (1);
      }
/* Added by DMZ to have log files be etcdir/Mountpoint.cue etc */
        snprintf (set.cuefile, BUFSIZE, "%s/%s.cue", set.logdir, set.mount_name);
        snprintf (set.logfilename, BUFSIZE, "%s/%s.log", set.logdir, set.mount_name);
        snprintf (set.pidfile, BUFSIZE, "%s/%s.pid", set.logdir, set.mount_name);

      post_config ();

#ifdef _WIN32
      if (WSAStartup (0x202, &wsaData) == SOCKET_ERROR) {
            fprintf (stderr, "WSAStartup failed with error %d\n", WSAGetLastError ());
            WSACleanup ();
            return -1;
      }
#endif

      scream (VERBOSE, "Resolving hostname %s...\n", set.servername);

#ifdef _WIN32
      // 
      // Attempt to detect if we should call gethostbyname() or 
      // gethostbyaddr() 

      if (isalpha (set.servername[0])) {  /* server address is a name */
            hp = gethostbyname (set.servername);
      } else {          /* Convert nnn.nnn address to a usable one */
            addr = inet_addr (set.servername);
            hp = gethostbyaddr ((char *) &addr, 4, AF_INET);
      }
      if (hp == NULL) {
            fprintf (stderr, "Cannot resolve address [%s]: Error %d\n",
                   set.servername, WSAGetLastError ());
            px_shutdown (2);
      }
#else
      if ((hp = gethostbyname (set.servername)) == NULL) {
            scream (TOERROR, "Unknown host: [%s]\n", set.servername);
            px_shutdown (2);
      }
#endif
      scream (VERBOSE, "Creating socket\n");

      /* Create socket */
      if ((s = socket (AF_INET, SOCK_STREAM, 6)) < 0) {
            scream (TOERROR, "Could not create socket, exiting.\n");
            perror ("socket:");
            px_shutdown (3);
      }
      /* Create server adress */
      memset (&name, 0, sizeof (struct sockaddr_in));

      name.sin_family = AF_INET;
      name.sin_port = htons (set.port);
      memcpy (&name.sin_addr, hp->h_addr_list[0], hp->h_length);
      len = sizeof (struct sockaddr_in);

#ifndef _WIN32
      setup_signal_traps ();
#endif

      scream (VERBOSE, "Attempting connection to [%s:%d]\n", set.servername, set.port);

      /* Connect to the server */
      if (connect (s, (struct sockaddr *) &name, len) < 0) {
            scream (TOERROR, "ERROR connecting to [%s:%d]\n", set.servername, set.port);
            perror ("connect:");
            px_shutdown (4);
      }
      scream (NORMAL, "Connected: [%s:%d\\%s]\n", set.servername, set.port, set.mount_name);

      scream (VERBOSE, "Starting main source streaming loop..\n");
      play_loop ();

      scream (VERBOSE, "Shutting down\n");
      px_shutdown (0);
      return 0;
}
#ifndef _WIN32
void
setup_signal_traps ()
{
#ifdef BROKEN_DEBUG
      scream (VERBOSE, "Activating signal handlers..\n");
#endif

#if (defined(SYSV) && !defined(hpux)) || defined(SVR4)
#define signal(x,y) sigset(x,y)
#endif
      
#ifdef hpux
      signal (SIGINT, s1gnal);
      signal (SIGCHLD, s1gnal);
#else
      signal (SIGSEGV, s1gnal);
      signal (SIGPIPE, s1gnal);
      signal (SIGINT, s1gnal);
      signal (SIGFPE, s1gnal);
#ifndef IRIX
      signal (SIGBUS, s1gnal);
#endif
      signal (SIGHUP, s1gnal);
      signal (SIGUSR1, s1gnal);
      signal (SIGUSR2, s1gnal);
      signal (SIGCHLD, s1gnal);
      signal (SIGIO, s1gnal);
      signal (SIGALRM, SIG_IGN);
#endif
}

#endif /* !win32 */

/* This is going to be messy when configuration files enter the room */
void
setup_defaults ()
{
      char path[BUFSIZE] = "";

      set.use_id3 = 0;
      set.setup_playlist = 0;
      set.shuffle_playlist = 0;
      set.loop = 0;
      set.shortfilenames = 0;
      set.truncate = 1;
      set.verbose = 0;
      set.use_icy = 0;
      set.logfilename[0] = '\0';
      set.logfile = NULL;
      set.current_bitrate = DEFAULT_BITRATE;
      set.overhead = 0.01;
      set.buffer_overhead = 0.001;
      set.autocorrection = 0;
      set.use_cue_file = 1;
      set.use_dj = 0;
      set.logged_in = 0;
      set.titlestreaming = 0;
      set.daemon = 0;
      set.autodetection = 1;
      set.public = 1;
      set.update_cue_file = 1;
      set.skip = 0;
      set.graphics = 1;
      set.port = PORTNUM;
      set.autodump[0] = '\0';

#ifdef _WIN32
      _getcwd (path, BUFSIZE);
      my_snprintf(set.logdir, BUFSIZE, "%s%c%s", path, DELIMITER, "log");
      my_snprintf(set.etcdir, BUFSIZE, "%s%c%s", path, DELIMITER, "etc");
#else
      set.logdir = strdup (LOGDIR);
      set.etcdir = strdup (ETCDIR);
#endif

#ifndef _WIN32                /* use current dir for WIN32 */
    my_snprintf5 (set.playlist, BUFSIZE, "%s/%s.playlist", set.logdir, MOUNTPOINT);
      my_snprintf5 (set.cuefile, BUFSIZE, "%s/%s.cue", set.logdir, MOUNTPOINT);
      my_snprintf5 (set.logfilename, BUFSIZE, "%s/%s.log", set.logdir, MOUNTPOINT);
      my_snprintf5 (set.pidfile, BUFSIZE, "%s/%s.pid", set.logdir, MOUNTPOINT);
#else
    my_snprintf5 (set.playlist, BUFSIZE, "%s\\%s.playlist", set.logdir, MOUNTPOINT);
      my_snprintf5 (set.cuefile, BUFSIZE, "%s\\%s.cue", set.logdir, MOUNTPOINT);
      my_snprintf5 (set.logfilename, BUFSIZE, "%s\\%s.log", set.logdir, MOUNTPOINT);
      my_snprintf5 (set.pidfile, BUFSIZE, "%s\\%s.pid", set.logdir, MOUNTPOINT);
#endif

      strncpy (set.configfile, DEFAULT_CONFIG_FILE, BUFSIZE);
      strncpy (set.password, PASSWORD, BUFSIZE);
      strncpy (set.djfile, DJPROGRAM, BUFSIZE);
      strncpy (set.url, URL, BUFSIZE);
      strncpy (set.genre, GENRE, BUFSIZE);
      strncpy (set.name, NAME, BUFSIZE);
      strncpy (set.description, DESCRIPTION, BUFSIZE);
      strncpy (set.mount_name, MOUNTPOINT, BUFSIZE);
}

void
post_config ()
{
    char path[BUFSIZE] = "";
      struct stat st;

    strcpy (path, set.logdir);

#ifndef _WIN32                /* use current dir for WIN32 */
      if ((stat (path, &st) == -1) || (!S_ISDIR (st.st_mode))) {
            scream (TOERROR, "[%s] directory does not exist, trying to create\n", path);
            if (mkdir (path, 00755) == -1) {
                  scream (TOERROR, "Could not create directory [%s], exiting\n",
                        path);
            }
      } 
    
    strcpy (path, set.etcdir);
      if ((stat (path, &st) == -1) || (!S_ISDIR (st.st_mode))) {
            scream (TOERROR, "[%s] directory does not exist, trying to create\n", path);
            if (mkdir (path, 00755) == -1) {
#else
    if ((stat (path, &st) == -1) || (!(st.st_mode & _S_IFDIR))) {
            scream (TOERROR, "[%s] directory does not exist, trying to create\n", path);
            if (!CreateDirectory(path, NULL)) {
                  scream (TOERROR, "Could not create directory [%s], exiting\n",
                        path);
            }
      }

    strcpy (path, set.etcdir);
    if ((stat (path, &st) == -1) || (!(st.st_mode & _S_IFDIR))) {
            scream (TOERROR, "[%s] directory does not exist, trying to create\n", path);
            if (!CreateDirectory(path, NULL)) {
#endif
                  scream (TOERROR, "Could not create directory [%s], exiting\n",
                        path);
            }
      }

      if ((set.logfile = fopen (set.logfilename, "w")) == NULL) {
            scream (TOERROR, "Could not open logfile [%s], exiting\n", set.logfile);
            px_shutdown (40);
      }
#ifndef _WIN32
      /* Into the backgroun if we should */
      if (set.daemon == 1) {
            int icepid = fork ();

            if (icepid == -1) {
                  scream (VERBOSE, "Can't fork, damn!\n");
                  px_shutdown (41);
            }
            if (icepid != 0) {
                  printf ("Light's out, going into the background, (pid: %d)\n\n",
                        icepid);
#if HAVE_SETPGID
                  setpgid (icepid, icepid);
#endif
                  exit (0);
            } else {
#if HAVE_SETPGID
                  setpgid (0, 0);
#endif
                  freopen ("/dev/null", "r", stdin);
                  freopen ("/dev/null", "w", stdout);
                  freopen ("/dev/null", "w", stderr);
                  close (0);
                  close (1);
                  close (2);
            }
      }
      /* Add the pidfile */
      {
            char pid[30];
            FILE *fp;

            if ((fp = fopen (set.pidfile, "w")) == NULL) {
                  scream (TOERROR, "Could not open pidfile %s, oops\n", set.pidfile);
                  perror ("fopen");
                  px_shutdown (44);
            }
            my_snprintf (pid, BUFSIZE, "%d\n", (int) getpid ());
            fputs (pid, fp);
            fclose (fp);
      }
#endif /* !win32 */


}


void
usage ()
{
      printf ("Usage: shout <host> [options] [[-b <bitrate] file.mp3]...\n");
      printf ("Options:\n");
/*    printf ("\t-B <directory>\t- Use directory for all shout's files.\n");*/
      printf ("\t-C <file>\t- Use file as configuration file (default is shout.conf)\n");
      printf ("\t-D <dj_file>\t- Run this before every song (system())\n");
      printf ("\t-F\t\t- Remove directory paths from title streaming.\n");
      printf ("\t-P <password>\t- Use specified password\n");
      printf ("\t-S\t\t- Display all settings and exit\n");
      printf ("\t-V\t\t- Use verbose output\n");
      printf ("\t-X <desc>\t- Use specified description.\n");
      printf ("\t-a\t\t- Turn on automatic bitrate (transfer) correction\n");
      printf ("\t-b <bitrate>\t- Start using specified bitrate\n");
      printf ("\t-d\t\t- Activate the dj.\n");
      printf ("\t-e <port>\t- Connect to port on server.\n");
      printf ("\t-f\t\t- Skip files that don't match the specified bitrate\n");
      printf ("\t-g <genre>\t- Use specified genre\n");
      printf ("\t-h\t\t- Show this text\n");
      printf ("\t-i\t\t- Use old icy headers\n");
      printf ("\t-k\t\t- Don't truncate the internal playlist (continue)\n");
      printf ("\t-l\t\t- Go on forever (loop)\n");
      printf ("\t-m <mount>\t- Use specified mount point\n");
      printf ("\t-n <name>\t- Use specified name\n");
      printf ("\t-o\t\t- Turn off the bitrate autodetection.\n");
      printf ("\t-p <playlist>\t- Use specified file as a playlist\n");
      printf ("\t-r\t\t- Shuffle playlist (random play)\n");
      printf ("\t-u <url>\t- Use specified url\n");
      printf ("\t-v\t\t- Show version\n");
      printf ("\t-x\t\t- Don't update the cue file (saves cpu)\n");
      printf ("\t-z\t\t- Go into the background (Daemon mode)\n");
      printf ("\t-t\t\t- Enable title streaming\n");
      printf ("\t-3\t\t- Use ID3 tags for streaming\n");
      printf ("\nIf no options are specified, all values are taken from the default config file\n");
}

void
find_config_file (int argc, char **argv)
{
      int i;

      for (i = 1; i < argc; i++) {
            if (argv[i][0] == '-') {
                  if ( argv[i][1] == 'C' ) { 
                        strncpy (set.configfile, argv[i + 1], BUFSIZE);
                        return;
                  }
            }
            i++;
      }
}

int
parse_arguments (int argc, char **argv)
{
      int i;
      char *c;

      scream (VERBOSE, "Parsing arguments...\n");
      if (argc == 1) {  /* No arguments */
            return 0;
      }

      if (argv[1][0] != '-') {
            strncpy (set.servername, argv[1], BUFSIZE);
      }

      for (i = 1; i < argc; i++) {
            if (argv[i][0] == '-') {
                  if ((c = strchr ("pmbeungAXCDP", argv[i][1])) != NULL) {
                        if ((i == (argc - 1)) || (argv[i + 1][0] == '-')) {
                              scream (TOERROR, "option %s requires an argument\n",
                                    argv[i]);
                              usage ();
                              px_shutdown(99);
                        }
                  }

                  switch (argv[i][1]) {
                        case '3':
                              set.use_id3 = 1;
                              break;
                        case 'A':
                              strncpy (set.autodump, argv[i + 1], BUFSIZE);
                              i++;
                              break;
                case 'B':
/* no more, use %s.conf in etc directory now 
#ifndef _WIN32
                              if(set.setup_playlist) {
                                    scream(TOERROR,"DOh! Sorry -B needs to be placed before specifying a playlist, sorry\n");
                                    scream(TOERROR,"This may not work as expected\n");
                              }
                              strncpy (set.base, argv[i + 1], BUFSIZE);
#endif */ /* WIN32 use current dir */
                              i++;
                              break;
                        case 'C':
                              /* we parse this earlier */
                              i++;
                              break;
                        case 'D':   /* Implicitly -d */
                              strncpy (set.djfile, argv[i + 1], BUFSIZE);
                              set.use_dj = 1;
                              i++;
                              break;
                        case 'F':   /* Remove directory path info from title streaming */
                              set.shortfilenames = 1;
                              break;
                        case 'P':
                              strncpy (set.password, argv[i + 1], BUFSIZE);
                              i++;
                              break;
                        case 'S':
                              show_settings ();
                              px_shutdown (0);
                              break;
                        case 'V':
                              set.verbose = 1;
                              break;
                        case 'X':
                              strncpy (set.description, argv[i + 1], BUFSIZE);
                              i++;
                              break;
                        case 'a':
                              set.autocorrection = 1;
                              break;
                        case 'b':
                              set.current_bitrate = atoi (argv[i + 1]);
                              i++;
                              break;
                        case 'd':
                              set.use_dj = 1;
                              break;
                        case 'e':
                              set.port = atoi (argv[i + 1]);
                              i++;
                              break;
                        case 'f':
                              set.skip = 1;
                              break;
                        case 'g':
                              strncpy (set.genre, argv[i + 1], BUFSIZE);
                              i++;
                              break;
                        case 'h':
                              usage ();
                              px_shutdown(99);
                              break;
                        case 'i':
                              set.use_icy = 1;
                              break;
                        case 'k':
                              set.truncate = 0;
                              break;
                        case 'l':
                              set.loop = 1;
                              break;
                        case 'o':
                              set.autodetection = 0;
                              break;
                        case 'm':
                              strncpy (set.mount_name, argv[i + 1], BUFSIZE);
                              i++;
                              break;
                        case 'n':
                              strncpy (set.name, argv[i + 1], BUFSIZE);
                              i++;
                              break;
                        case 'p':
                              if (!set.setup_playlist)
                                    setup_playlist ();
                              add_list_to_playlist (argv[i + 1]);
                              i++;
                              break;
                        case 'r':
                              set.shuffle_playlist = 1;
                              break;
                        case 's':
                              set.public = 0;
                              break;
                        case 't':
                              set.titlestreaming = 1;
                              break;
                        case 'u':
                              strncpy (set.url, argv[i + 1], BUFSIZE);
                              i++;
                              break;
                        case 'v':
                              scream (NORMAL, "%s <eel@musiknet.se>\n", VERSION);
                              px_shutdown(99);
                              break;
                        case 'x':
                              set.update_cue_file = 0;
                              break;
                        case 'z':
                              set.daemon = 1;
                              break;
                        default:
                              scream (TOERROR, "Unknown option %s\n", argv[i]);
                              usage ();
                              px_shutdown(99);
                              break;
                  }
            } else if (i != 1) {
                  if (!set.setup_playlist)
                        setup_playlist ();
                  add_file_to_playlist (argv[i]);
            }
      }
      return 1;
}

void
add_list_to_playlist (char *list)
{
      FILE *fp, *listfp;
      char *c;
      char filename[BUFSIZE], line[BUFSIZE], full_line[BUFSIZE + 20];
      int rate = 0;

      if ((c = strchr (list, FDELIM)) != NULL) {
            /* Bitrate specified in filename:bitrate */
            splitc (filename, list, FDELIM);
            rate = atoi (list);
            scream (VERBOSE,
               "Adding list %s with bitrate %d (default not changed)\n",
                  filename, rate);
      } else {
            strncpy (filename, list, BUFSIZE);
            scream (VERBOSE, "Adding list %s without bitrate\n", filename);
      }

      if ((listfp = fopen (list, "r")) == NULL) {
            scream (TOERROR, "Could not open playlist %s\n", list);
            px_shutdown (EXISTS);
            return;
      }
      if ((fp = fopen (set.playlist, "a")) == NULL) {
            scream (TOERROR, "Could not append to internal playlist, exiting\n");
            perror ("fopen");
            px_shutdown (7);
      }
      while (fgets (line, BUFSIZE, listfp)) {
            if (rate != 0) {
                  /* Deal with the \n */
                  if (line[strlen (line) - 1] == '\n')
                        line[strlen (line) - 1] = '\n';
                  my_snprintf5 (full_line, BUFSIZE, "%s;;%d\n", line, rate);
            } else
                  strncpy (full_line, line, BUFSIZE);
            if (fputs (full_line, fp) == EOF) {
                  scream (TOERROR, "Could not write to internal playlist, exiting\n");
                  perror ("fputs");
                  px_shutdown (8);
            }
      }
      fclose (listfp);
      fclose (fp);
}

void
add_file_to_playlist (char *file)
{
      FILE *fp;
      char *c;
      char filename[BUFSIZE], line[BUFSIZE];
      int rate = 0;

      if ((c = strchr (file, FDELIM)) != NULL) {
            /* Bitrate specified in filename:bitrate */
            splitc (filename, file, FDELIM);
            rate = atoi (file);
            scream (VERBOSE, "Adding %s with bitrate %d (default not changed)\n",
                  filename, rate);
      } else {
            strncpy (filename, file, BUFSIZE);
            scream (VERBOSE, "Adding %s without bitrate\n", filename);
      }

      if ((fp = fopen (set.playlist, "a")) == NULL) {
            scream (TOERROR, "Could not append to internal playlist, exiting\n");
            perror ("fopen");
            px_shutdown (9);
      }

      if (rate)
      {
            my_snprintf5 (line, BUFSIZE, "%s;;%d\n", filename, ((rate > 0) ? rate : set.current_bitrate));
      } else {
            my_snprintf (line, BUFSIZE, "%s\n", filename);
      }

      if (fputs (line, fp) == EOF) {
            scream (TOERROR, "Could not write to end of playlist, exiting\n");
            perror ("fputs");
            px_shutdown (10);
      }
      fclose (fp);
}

void
setup_playlist ()
{
      int fd;
      struct stat st;
    char path[BUFSIZE] = "";

    /* Added by DMZ to make playlist Mountpoint.playlist */
    snprintf (set.playlist, BUFSIZE, "%s/%s.playlist", set.logdir, set.mount_name);
    strcpy (path, set.logdir);
#ifndef _WIN32
      if ((stat (path, &st) == -1) || (!S_ISDIR (st.st_mode))) {
            scream (TOERROR, "[%s] directory does not exist, trying to create\n", path);
      
            if (mkdir (path, 00755) == -1) {
                  scream (TOERROR, "Could not create directory [%s], exiting\n", path);
            }
      }

    strcpy (path, set.etcdir);
      if ((stat (path, &st) == -1) || (!S_ISDIR (st.st_mode))) {
            scream (TOERROR, "[%s] directory does not exist, trying to create\n", path);
        if (mkdir (path, 00755) == -1) {
#else
      if ((stat (path, &st) == -1) || (!(st.st_mode & _S_IFDIR))) {
            scream (TOERROR, "[%s] directory does not exist, trying to create\n", path);            
            if (!CreateDirectory(path, NULL)) {
                        scream (TOERROR, "Could not create directory [%s], exiting\n", path);
            }
      }

    strcpy (path, set.etcdir);
      if ((stat (path, &st) == -1) || (!(st.st_mode & _S_IFDIR))) {
            scream (TOERROR, "[%s] directory does not exist, trying to create\n", path);           
            if (!CreateDirectory(path, NULL)) {
#endif
            scream (TOERROR, "Could not create directory [%s], exiting\n",
                        path);
            }
      }

      if (set.truncate) {
            if ((fd = open (set.playlist, O_CREAT | O_TRUNC | O_RDWR, 00644)) < 0) {
                  scream (TOERROR, "Could not create internal playlist file %s\n",
                        set.playlist);
                  perror ("open");
                  px_shutdown (11);
            }
      } else if ((fd = open (set.playlist, O_CREAT | O_RDWR, 00644)) < 0) {
            scream (TOERROR, "Could not create internal playlist file %s\n",
                  set.playlist);
            perror ("open");
            px_shutdown (12);
      }
      close (fd);
      set.setup_playlist = 1;
}

/* This shuffles the internal playlist.
 * The rand_file function is in the file rand.c
 * I've just modified that file slighly for use in shout.
 * rand.c was written by Erik Greenwald <br0ke@math.smsu.edu>, 
 * who deserves due credit. */
void
shuffle ()
{
      FILE *fp, *tmp;

#ifdef _WIN32
      char *tmp_name = tempnam (set.logdir, "shout");

#else
      char *tmp_name = tempnam (set.logdir, ".shout");

#endif
      struct stat st;

      if (!tmp_name) {
            scream (TOERROR, "Could not create unique temporary filename, exiting\n");
            px_shutdown (12);
      }
      scream (VERBOSE, "Shuffling playlist...\n");
      if ((tmp = fopen (tmp_name, "w")) == NULL) {
            scream (TOERROR, "Could not create temporary file, exiting.");
            perror ("fopen");
            px_shutdown (13);
      }
      stat (set.playlist, &st);

      if (st.st_size <= 0) {
            scream (TOERROR, "Damn you, the playlist is a zero length file!\n");
            px_shutdown (49);
      }
      if ((fp = fopen (set.playlist, "r")) == NULL) {
            scream (TOERROR, "Could not open %s, exiting.\n", set.playlist);
            perror ("fopen");
            px_shutdown (14);
      }
      rand_file (fp, tmp);

      fclose (fp);
      fclose (tmp);

#ifdef _WIN32
      remove (set.playlist);
#endif

      if (rename (tmp_name, set.playlist) < 0) {
            scream (TOERROR, "Could not rename %s to %s, exiting.\n", tmp_name,
                  set.playlist);
            perror ("rename");
            px_shutdown (15);
      }


      set.playlist_index = 0;
      remove (tmp_name);
      nfree (tmp_name);
      scream (VERBOSE, "Done shuffling..\n");
}

void
play_loop ()
{
      do {
            if (intflag)
                  px_shutdown (33);
            valid_song_found = 0;
            current_song = 0;
            if (set.shuffle_playlist)
                  shuffle ();

            while (current_song >= 0) {
                  /* Magic starts here
                   * Let's check the time here, and at the start of the transfer,
                   * so we can justify for the autodetection and stuff */
#ifndef _WIN32
                  gettimeofday (&shoutstart, NULL);
#endif
                  set.latency = my_get_time ();
                  current_song = play_from_playlist (current_song);
                  if (intflag)
                        intflag = 0;
            }
      } while (set.loop);
}

#ifndef _WIN32
void
s1gnal (const int sig)
{
      char path[BUFSIZE] = "";

      setup_signal_traps ();

      switch (sig) {
            case SIGUSR1:
                  scream (VERBOSE, "Caught signal %d, shuffling playlist\n", sig);
                  shuffle ();
                  break;
            case SIGUSR2:
                  scream (VERBOSE, "Caught signal %d, reconnecting to server\n", sig);
                  /* connect_to_server (); */
                  break;
            case SIGHUP:
                  scream (VERBOSE, "Caught signal %d, rereading config file\n", sig);
                  strcpy (path, set.etcdir);
                  parse_config_file (path, set.configfile);
                  break;
            case SIGSEGV:
#ifndef IRIX
            case SIGBUS:
                  scream (TOERROR, "Caught signal %d, we're dead! :)\n", sig);
                  px_shutdown (16);
                  break;
#endif
            case SIGFPE:
                  scream (TOERROR, "Gee, what did we do there?\n");
                  px_shutdown (17);
                  break;
            case SIGIO:
                  scream (TOERROR, "Caught signal %d, what's the server up to?\n", sig);
                  px_shutdown (19);
                  break;
            case SIGINT:
                  {
                        struct timeval tv;

                        gettimeofday (&tv, NULL);
                        if (((tv.tv_sec + tv.tv_usec / 1000000.0) - 0.4)
                            < (lastint.tv_sec + lastint.tv_usec / 1000000.0))
                              px_shutdown (33);
                        gettimeofday (&lastint, NULL);
                        intflag = 1;
                        fflush (stdout);
                        printf ("\n");
                        fflush (stdout);
                  }
                  break;
            case SIGCHLD:
                  {
                        pid_t pid;
                        int stat;

                        pid = wait (&stat);
                  }
                  break;
      }

      /*
      * If we're using a non-BSDish system, the signal handlers may have been
      * reset to their default when raised so we have to set them again.
      */
      setup_signal_traps();
}
#endif /* ! _WIN32 */

int
play_from_playlist (const int which_line)
{
      int i;
      char line[BUFSIZE], crate[BUFSIZE], drate[BUFSIZE];
      FILE *fp = NULL;

      if (intflag > 1)
            px_shutdown (33);

      if ((fp = fopen (set.playlist, "r")) == NULL) {
            scream (TOERROR, "Could not open %s, errno: %s\n", set.playlist, strerror (errno));
            fclose (fp);
            perror ("fopen");
            px_shutdown (18);
      }
      if (which_line < 0) {
            scream (TOERROR, "Dammit, negative line number? [%d]\n", which_line);
            fclose (fp);
            return -1;
      }
      /* Skip to the correct line */
      for (i = 0; i <= which_line; i++) {
            if (fgets (line, BUFSIZE, fp) == NULL) {  /* End of file */
                  if (which_line == 0) {  /* Empty file? */
                        scream (TOERROR, "That would be an empty file, exiting\n");
                        fclose (fp);
                        px_shutdown (19);
                  } else if (!valid_song_found) {
                        scream (TOERROR, "I can't find any songs in your playlist, exiting\n");
                        px_shutdown (19);
                  }
                  fclose (fp);
                  return -1;
            }
      }
      fclose (fp);

      set.playlist_index = which_line;

      scream (VERBOSE, "\nPlaying from %s, line %d\n", set.playlist, which_line + 1);
      /* Changes be here, song:command:bitrate
       * or just song:command
       * or just song */

      /* Split the line into name, bitrate and command */
      if (splitc (crate, line, FDELIM) == NULL) {
            scream (VERBOSE, "No bitrate or command specified, using autodetect\n");
            play_song (line, 0, NULL);
            return which_line + 1;
      }
      if (splitc (drate, line, FDELIM) == NULL) {
            scream (VERBOSE, "Command but no bitrate found, using autodetect\n");
            play_song (crate, 0, line);
            return which_line + 1;
      }
      scream (VERBOSE, "Command and bitrate found, using that\n");
      if (!drate[0] || (strlen (drate) < 2))
            strcpy (drate, set.djfile);
      play_song (crate, atoi (line), drate);
      return which_line + 1;
}

void
put_in_cue_file (char *filename, int size, int rate, int seconds, int played,
             int index)
{
      char line[4096];
      FILE *fp, *temp;
      int minutes = (int) (seconds / 60);
      int nseconds = seconds - (minutes * 60);
      int per;

      char song_name[31];
      char artist[31];
      char tag[3];

      if (set.use_id3 && seconds == 0) /* Only the first time */
      {
            memset (song_name, 0, 31);
            memset (artist, 0, 31);
            memset (tag, 0, 3);

            if (!(temp = fopen (filename, "r")))
                  return;
            
            fseek (temp, -128, SEEK_END);
            
            fread (tag, sizeof (char), 3, temp);
            
            if (strncmp (tag, "TAG", 3) == 0) 
            {
                  fseek (temp, -125, SEEK_END);
                  
                  fread (song_name, 1, 30, temp);
                  
                  while (song_name[strlen (song_name) - 1] == '\040') 
                        song_name[strlen (song_name) -1] = '\000';
                  
                  fread (artist, 1, 30, temp);
                  
                  while (artist[strlen (artist) - 1] == '\040') 
                        artist[strlen (artist) - 1] = '\000';
                  
            }
            
            fclose(temp);
      }

      if (size)
            per = (int)(((double) played / (double) size) * 100.0);
      else
            per = 0;
      if ((fp = fopen (set.cuefile, "w")) == NULL) {
            scream (TOERROR, "Could not open cue file %s, exiting\n", set.cuefile);
            perror ("fopen");
            px_shutdown (20);
      }
      /* New syntax of cue file
       * filename
       * size
       * rate
       * minutes:seconds total
       * % played 
       * current line in playlist
       * artist
       * songname
       */
#ifdef HAVE_SNPRINTF
      if (set.use_id3 && seconds == 0) 
        {
          snprintf (line, 4096, "%s\n%d\n%d\n%d:%.2d\n%d\n%d\n%s\n%s\n", filename, size, rate,
                  minutes, nseconds, per, index, artist, song_name);
        } else {
          snprintf (line, 4096, "%s\n%d\n%d\n%d:%.2d\n%d\n%d\n", filename, size, rate,
                  minutes, nseconds, per, index);
        }
#else
      if (set.use_id3 && seconds == 0) 
        {
          sprintf (line, "%s\n%d\n%d\n%d:%.2d\n%d\n%d\n%s\n%s\n", filename, size, rate,
                 minutes, nseconds, per, index, artist, song_name);
        } else {
          sprintf (line, "%s\n%d\n%d\n%d:%.2d\n%d\n%d\n", filename, size, rate,
                 minutes, nseconds, per, index);
        }
#endif
      fputs (line, fp);
      fclose (fp);
}

void
do_the_dj_thing (const char *command)
{
      if (command && strlen (command) > 1) {
            scream (VERBOSE, "Running command: [%s]\n", command);
            system (command);
      } else
            scream (VERBOSE, "Invalid DJ command: [%s]\n", command);
}

/* The second most confusing function in the world,
 * next to the read_message() in s_bsd.c in the ircd source :)
 * Magic be here, in large quantities. */
void
play_song (char *ap, int rate, const char *command)
{
      int fd, i;
      long bufsize, n, bytes, slice = 0, dots = 0, seconds = 0;
      long unsigned int lowest = 1000000;
      my_long_t deltasleep = 0, start = 0, t = 0, mtv = 0;
      char *buf;
      struct stat st;
      int tmp=0;

      /* Clean the filename from \n */
      if (ap[strlen (ap) - 1] == '\n')
            ap[strlen (ap) - 1] = '\0';
      /* Open our file */
      if ((fd = open (ap, O_RDONLY | O_BINARY)) < 0) {
            scream (TOERROR, "Could not access [%s]\n", ap);
            perror ("open");
            close (fd);
            exit_or_return (EXISTS);
            return;
      }
      /* Get the size of it */
      fstat (fd, &st);


#ifdef _WIN32
      if (st.st_mode & _S_IFDIR)
#else
      if (S_ISDIR (st.st_mode))
#endif /* WIN32 */
      {
            scream (VERBOSE, "Skipping directory %s\n", ap);
            close (fd);
            return;
      }
#ifndef _WIN32
      if (S_ISFIFO (st.st_mode)) {
            set.graphics = 0;
      }
#endif /* !win32 */

      if (rate == 0) {
            if (set.autodetection) {
                  scream (VERBOSE, "Checking mpeg headers ...\n");
                  rate = 1000 * bitrate_of (ap);
                  if (rate == 0)
                        scream (NORMAL, "Bitrate autodetection failed, using default!\n");
            }
      }
      if (set.skip && (rate > 0) && rate != set.current_bitrate) {
            close (fd);
            scream (VERBOSE, "Skipping file, not correct bitrate\n");
            return;
      }
      if (rate <= 0)          /* Either no autodetect, or autodetect failed */
            rate = set.current_bitrate;
      else
            set.current_bitrate = rate;

      if (rate == 0) {
            scream (TOERROR,
            "No automatic nor user specified bitrate found, exiting\n");
            px_shutdown (33);
      }
#ifndef _WIN32
      if (set.use_dj) {
            if (!command || !command[0] || strlen (command) < 2)
                  command = set.djfile;
            do_the_dj_thing (command);
      }
#endif /* !WIN32 */

      if (set.graphics) {
            /* Some song info */
            long minutes, nseconds;

            slice = st.st_size / 78;
            seconds = st.st_size / (rate / 8);
            if (set.use_cue_file)
                  put_in_cue_file (ap, st.st_size, rate, seconds, 0, set.playlist_index);
            minutes = (int) (seconds / 60);
            nseconds = seconds - (minutes * 60);
            scream (NORMAL, "\n[%s]\n", ap);
            scream (NORMAL,
                  "[%d:%.2d] Size: %d Bitrate: %d (%d bytes/dot)\n",
                  minutes, nseconds, (int) st.st_size, rate, slice);
            /* The really fancy graphics */
#ifndef _WIN32
            for (i = 0; i < 79; i++)
                  printf (" ");
            printf ("]");
            for (i = 0; i < 80; i++)
                  printf ("\b");
            printf ("[");
#else
            printf (">");
#endif
      }
      fflush (stdout);

      if (!set.logged_in)
            login ();

#ifndef _WIN32
      if (set.titlestreaming) {
            int icepid = fork ();

            if (icepid == -1) {
                  scream (VERBOSE, "CAN'T FORK DAMMIT!\n");
            } else if (icepid == 0) {
                  setup_signal_traps ();
                  update_meta_info_on_server (ap, st.st_size);
                  exit (0);
            }
      }
#else
      if (set.titlestreaming) {
            update_meta_info_on_server (ap, st.st_size);
      }
#endif

      /* Note that bytes != bits */
      bufsize = (long)((rate / 8) * (1.0 + set.buffer_overhead));
      buf = (char *) nmalloc (bufsize + 200);

      start = my_get_time ();
      bytes = 0;
      valid_song_found = 1;

      /* This is the time we shouldn't sleep (cause it took us this long
       * to get here */
      deltasleep = (start - set.latency);

      if (set.playlist_index == 0) {      /* Since we haven't started writing yet,
                               * we have nothing to keep up with */
            deltasleep = 0;
            set.latency = my_get_time ();
      }
      if (deltasleep < 0)
            deltasleep = 0;

      /* The main playing loop, magic be here */
      while (42) {
            int bytes_left, bytes_read;

            t = my_get_time ();

            bytes_left = DEFAULT_BUFFER_SIZE;

            if (bytes_left > bufsize)
                  bytes_left = bufsize;
            bytes_read = 0;
            /* <pradman@iki.fi> is guilty of the smoothness in this do-loop.
             * Now it makes sure that we've actually read bufsize bytes, before
             * it goes into this second's sleep. */
            do {
                  /* Read up to bytes_left bytes from the file */
#ifdef _WIN32
                  if ((n = read (fd, buf, bytes_left)) < 0)
#else
                  if ((n = read (fd, buf, bytes_left)) < 0 && !is_recoverable (errno))
#endif
                  {
                        printf ("Error in read\n");
                        close (fd);
                        nfree (buf);
                        exit_or_return (READ);
                        return;
                  }
                  /* The last 128 bytes _MIGHT_ be a id3 tag */
                  if ((bytes + n) > (st.st_size - 128)) {
                        char *id3start;
                        int newreads = 0;

                        while ((bytes + n) < st.st_size) {
                              /* The size here _should_ be bytes_left - n
                               * For some reason, this is not working, so
                               * I'm doing just bytes_left. Which should be
                               * fine too. */
                              if (n > bufsize + 200) {
                                    scream (TOERROR, "Erroneous filesize, aborting\n");
                                    px_shutdown (33);
                              }
                              newreads = read (fd, &buf[n], bytes_left);
                              if (newreads == 0)
                                    break;      /* File size changed? */

                              if (newreads < 0 && !is_recoverable (errno))
                              {
                                    printf ("Error in read\n");
                                    close (fd);
                                    nfree (buf);
                                    exit_or_return (READ);
                                    return;
                              }
                              n = n + newreads;
                        }

                        if (n < 128)
                              printf ("Damn, no 128 bytes available in tail!\n");
                        else {
                              id3start = &buf[n - 128];
                              if (strncmp (id3start, "TAG", 3) == 0) {
                                    scream (VERBOSE, "Skipping ID3 tag\n");
                                    n -= 128;
                              }
                              bytes += n;
                              tmp = send (s, buf, n, 0);
                              if (tmp < 0 && !is_recoverable (errno)) {
                                    scream (VERBOSE, "Server kicked us out, damn.\n");
                                    px_shutdown (77);
                              }

                              n = 0;
                              mtv = my_get_time ();
                        }
                  }
                  if (n <= 0) {     /* End of file */
                        my_long_t time_sent;
                        double avg;

                        if (set.graphics) {
                              if (dots < 78)
                                    while (dots < 78)
                                          printf ("."), dots++;
                        }
                        time_sent = (t - set.latency);
                        if (!rate || !time_sent) {
                              nfree (buf);
                              close (fd);
                        }
#ifdef HAVE_LONG_LONG
                        scream (NORMAL,
                              "\nDone:\n Sent %d bytes in %qu.%qu seconds\n", bytes,
                          time_sent / 1000000, time_sent % 1000000);
#else
                        scream (NORMAL,
                              "\nDone:\n Sent %d bytes in %lu.%lu seconds\n", bytes,
                          time_sent / 1000000, time_sent % 1000000);
#endif
                        if (t - start <= 0)
                              scream (NORMAL, "Gee, that went fast! :)\n");
                        else {
                              avg = (double) (8.0 * (bytes / ((long double) time_sent
                                               / 1000000.0)));
                              scream (NORMAL, "Transfer rate average %lfbps\n", avg);
                              scream (NORMAL, "Lowest sleep time: %lu microseconds\n",
                                    lowest);
                              if (set.autocorrection) {
                                    if (((double) (rate - avg) / (double) rate) > 0.2)
                                          scream (NORMAL, "Wicked transfer rate, ignoring\n");
                                    else {
                                          set.buffer_overhead += (1.0 - (avg / (double) rate));
                                          if (set.buffer_overhead < 0)
                                                set.buffer_overhead = 0;
                                          scream (NORMAL,
                                                "Now using an overhead factor of %f\n",
                                          set.buffer_overhead);
                                    }
                              }
                        }
                        nfree (buf);
                        close (fd);
                        return;
                  }
                  i = 0;
                  do {
                        tmp = send (s, &buf[i], n - i, 0);

                        if (tmp < 0 && !is_recoverable (errno)) {
                              scream (VERBOSE, "Server kicked us out, damn.\n");
                              px_shutdown (77);
                        }
                        i += tmp;
                  } while (i < n);

                  bytes_read += n;
                  bytes += n;
                  if (bytes_read + bytes_left > bufsize)
                        bytes_left = bufsize - bytes_read;
            } while (bytes_read < bufsize);

            if (set.graphics && (bytes > (slice * (dots + 1)))) {
                  if (set.use_cue_file && set.update_cue_file)
                        put_in_cue_file (ap, st.st_size, rate, seconds, bytes,
                                     set.playlist_index);
                  printf (".");
                  fflush (stdout);
                  dots++;
            }
            if (intflag) {
                  nfree (buf);
                  close (fd);
                  return;
            }
            mtv = my_get_time ();

            if (((mtv - t)) > (my_long_t) 1000000) {
                  printf ("\b!");
                  deltasleep = (mtv - t) - (my_long_t) 1000000;
                  continue;
            }
            if (deltasleep > 1000000)
                  deltasleep -= 1000000;
            else {
                  my_long_t now;
                  double thismombitrate, thistotbitrate;
                  unsigned long int sleeptime = (unsigned long)((1.0 - (double) set.overhead)
                  * (1000000 - (mtv - t) - deltasleep));

                  if (sleeptime > 1000000)
                        sleeptime = 1000000;
#ifdef _WIN32
                  Sleep (sleeptime / multfactor);
#else
                  usleep (sleeptime);
#endif
                  if (sleeptime < lowest)
                        lowest = sleeptime;

                  now = my_get_time ();
                  thismombitrate = (bufsize * 8.0) / (double) (now - t)
                        * 1000000;
                  thistotbitrate = (bytes * 8.0)
                        / (double) (now - set.latency) * 1000000;
                  set.overhead += (((1.0 - (thismombitrate / (double) rate))
                     + (1.0 - (thistotbitrate / (double) rate)))) / 2;

                  if (set.overhead < 0)
                        set.overhead = 0;
            if (set.verbose==2)
                      printf ("total bitrate: %fbps current bitrate: %fbps \noverhead: %f sleeptime %lu usec\r",
                            thistotbitrate, thismombitrate, set.overhead, sleeptime);

                  deltasleep = 0;
            }
      }
      close (fd);
      nfree (buf);
}

void
scream (int where, char *how,...)
{
      va_list va;
      char buf[BUFSIZE];

      buf[0] = '\0';

      va_start (va, how);
      my_vsnprintf (buf, BUFSIZE, how, va);
      /* Log to file even if set.verbose is unset */
      if (set.logfile != NULL) {
            fputs (buf, set.logfile);
            fflush (set.logfile);
      }
      if (where == VERBOSE) {
            if (set.verbose)
                  printf (buf);
      } else if (where == TOERROR) {
            fprintf (stderr, buf);
      } else {
            printf (buf);
      }

      va_end (va);
}

#ifdef _WIN32
BOOL
WINAPI px_shutdown_evt (DWORD CtrlType)
{
      px_shutdown (CtrlType+100);
      return 1;
}
#endif

void 
px_shutdown (const int err)
{
      scream (VERBOSE, "Shutting it all down\n");
      if (set.logfile != NULL)
            fclose (set.logfile);
      shutdown (s, 2);
      remove (set.cuefile);


#ifdef _WIN32
      WSACleanup ();
      timeEndPeriod (1);
#else
      remove (set.pidfile);
#endif

      exit (err);
}

void
show_settings ()
{
      printf ("Compile time options:\n");
#ifdef DIE_ON_SMALL_ERRORS
      printf ("\tWill die on small errors\n");
#else
      printf ("\tWon't die on small errors\n");
#endif
      printf ("Defaults:\n");
      printf ("\tPassword: %s\n", PASSWORD);
      printf ("\tName: %s\n", NAME);
      printf ("\tGenre: %s\n", GENRE);
      printf ("\tURL: %s\n", URL);
#ifdef _WIN32
      printf ("\tShout directory: %s\n", set.base);
#else
      printf ("\tShout directory: %s\n", DEFAULT_BASE_DIR);
#endif
      printf ("\tDJ Program: %s\n", DJPROGRAM);
      printf ("\tConfig file: %s\n", DEFAULT_CONFIG_FILE);
      printf ("\tPort: %d\n", PORTNUM);
      printf ("\tBitrate: %d\n", DEFAULT_BITRATE);
      printf ("Current settings:\n");
      printf ("\tBitrate autodetection: %s\n", set.autodetection ? "on" : "off");
      printf ("\tPort to connect to: %d\n", set.port);
      printf ("\tShuffle playlist: %s\n", set.shuffle_playlist ? "on" : "off");
      printf ("\tLoop forever: %s\n", set.loop ? "on" : "off");
      printf ("\tShort title streaming: %s\n", set.shortfilenames ? "on" : "off");
      printf ("\tVerbose mode: %s\n", set.verbose ? "on" : "off");
      printf ("\tAutocorrection of transfer bitrate: %s\n",
            set.autocorrection ? "on" : "off");
      printf ("\tTruncate playlist: %s\n", set.truncate ? "on" : "off");
      printf ("\tUse cue file: %s\n", set.use_cue_file ? "yes" : "no");
      printf ("\tUpdate cue file: %s\n", set.update_cue_file ? "yes" : "no");
      printf ("\tUse DJ program: %s\n", set.use_dj ? "yes" : "no");
      printf ("\tPublic x-audio flag: %s\n", set.public ? "on" : "off");
      printf ("\tDefault bitrate: %d\n", set.current_bitrate);
      printf ("\tConfigfile: %s\n", set.configfile);
      printf ("\tInternal playlist: %s\n", set.playlist);
      printf ("\tCue file: %s\n", set.cuefile);
      printf ("\tLogfile: %s\n", set.logfilename);
      printf ("\tPassword: %s\n", set.password);
      printf ("\tDJ Program: %s\n", set.djfile);
      printf ("\tURL: %s\n", set.url);
      printf ("\tGenre: %s\n", set.genre);
      printf ("\tName: %s\n", set.name);
      printf ("\tDaemon: %d\n", set.daemon);
      printf ("\tArchive file (on server): %s\n", set.autodump[0] ? set.autodump : "n/a");
      return;
}

void
xaudio_login ()
{
      char buf[BUFSIZE];

      my_snprintf (buf, BUFSIZE, "SOURCE %s ", set.password);
      send (s, buf, strlen (buf), 0);
      scream (VERBOSE, "[%s]\n", buf);

      my_snprintf (buf, BUFSIZE, "/%s\n\n", set.mount_name[0] == '/' ? &set.mount_name[1] : set.mount_name);
      send (s, buf, strlen (buf), 0);
      scream (VERBOSE, "[%s]\n", buf);

      my_snprintf (buf, BUFSIZE, "x-audiocast-name:%s\n", set.name);
      send (s, buf, strlen (buf), 0);
      scream (VERBOSE, "[%s]\n", buf);

      my_snprintf (buf, BUFSIZE, "x-audiocast-genre:%s\n", set.genre);
      scream (VERBOSE, "[%s]\n", buf);
      send (s, buf, strlen (buf), 0);

      my_snprintf (buf, BUFSIZE, "x-audiocast-url:%s\n", set.url);
      scream (VERBOSE, "[%s]\n", buf);
      send (s, buf, strlen (buf), 0);

      my_snprintf (buf, BUFSIZE, "x-audiocast-public:%d\n", set.public);
      scream (VERBOSE, "[%s]\n", buf);
      send (s, buf, strlen (buf), 0);

      my_snprintf (buf, BUFSIZE, "x-audiocast-bitrate:%d\n", set.current_bitrate
                 / 1000);
      scream (VERBOSE, "[%s]\n", buf);
      send (s, buf, strlen (buf), 0);

      my_snprintf (buf, BUFSIZE, "x-audiocast-description:%s\n",
                 set.description);
      scream (VERBOSE, "[%s]\n", buf);
      send (s, buf, strlen (buf), 0);

      if (set.autodump[0])
      {
            my_snprintf (buf, BUFSIZE, "x-audiocast-dumpfile:%s\n",
                       set.autodump);
            scream (VERBOSE, "[%s]\n", buf);
            send (s, buf, strlen (buf), 0);
      }
      
      send (s, "\n", strlen ("\n"), 0);
}

void
icy_login ()
{
      char buf[BUFSIZE];
      int readbytes = 0, readb = 0;

      my_snprintf (buf, BUFSIZE, "%s\n", set.password);
      send (s, buf, strlen (buf), 0);

      errno = 0;

      do {
            readb = recv (s, &buf[readbytes], 100, 0);

            if (readb < 0 && !is_recoverable (errno))
            {
                  scream (TOERROR, "Error in read, exiting\n");
                  perror ("read");
                  px_shutdown (5);
            }
            if (readb > 0)
                  readbytes += readb;
      } while (readb <= 0);

      buf[readbytes] = '\0';

      if (buf[0] != 'O' && buf[0] != 'o') {
            scream (TOERROR, "Server error: [%s]\n", buf);
            px_shutdown (6);
      }
      my_snprintf (buf, BUFSIZE, "icy-name:%s\n", set.name);
      send (s, buf, strlen (buf), 0);

      my_snprintf (buf, BUFSIZE, "icy-genre:%s\n", set.genre);
      send (s, buf, strlen (buf), 0);

      my_snprintf (buf, BUFSIZE, "icy-url:%s\n", set.url);
      send (s, buf, strlen (buf), 0);

      my_snprintf (buf, BUFSIZE, "icy-pub:%d\n", set.public);
      send (s, buf, strlen (buf), 0);

      my_snprintf (buf, BUFSIZE, "icy-br:%d\n\n", set.current_bitrate / 1000);
      send (s, buf, strlen (buf), 0);
}

void
login ()
{
      char buf[BUFSIZE];
      int readbytes = 0, readb = 0;

      buf[0] = '\0';

      /* Login on server, then play all arguments as files */
      scream (VERBOSE, "Logging in...\n");

      if (set.use_icy)
            icy_login ();
      else {
            xaudio_login ();

            errno = 0;

            do {
                  readb = recv (s, &buf[readbytes], 100, 0);

                  if (readb < 0 && !is_recoverable (errno))
                  {
                        scream (TOERROR, "Error in read, exiting\n");
                        perror ("read");
                        px_shutdown (5);
                  }
                  if (readb > 0)
                        readbytes += readb;
            } while (readb <= 0);

            buf[readbytes] = '\0';

            if (buf[0] != 'O' && buf[0] != 'o') {
                  scream (TOERROR, "Server error: [%s]\n", buf);
                  px_shutdown (6);
            }
      }

      set.logged_in = 1;
}

#ifdef _WIN32
#define PDELIM '\\'
#else
#define PDELIM '/'
#endif

/* If you want you can do id3 additions here.. I don't have time */
void
update_meta_info_on_server (char *filename, unsigned long int size)
{
      sock_t sockfd = sock_connect (set.servername, set.port);
      char title[BUFSIZE];    /* copy of filename */
      char *song = NULL;
      char *mount = NULL;
      char *lastptr = NULL;   /* temporary ptr */
      char *titleptr = NULL;  /* ptr to shortened name */
      FILE *temp;
      char tag[3];
      char song_name[31];
      char artist[31];

      if (filename == NULL)
            return;
      
      title[0] = '\0'; /* a bag of paranoia a day, keeps the doctor away */

        memset(title, 0, BUFSIZE);
        memset(song_name, 0, 31);
        memset(artist, 0, 31);


      if (set.use_id3)
      {
            if (!(temp = fopen (filename, "r")))
                  return;

            fseek (temp, -128, SEEK_END);

            fread (tag, sizeof (char), 3, temp);

            if (strncmp (tag, "TAG", 3) == 0) 
            {
                  fseek (temp, -125, SEEK_END);

                  fread (song_name, 1, 30, temp);

                  while (song_name[strlen (song_name) - 1] == '\040') 
                        song_name[strlen (song_name) -1] = '\000';
                  
                  fread(artist, 1, 30, temp);
                  
                  while (artist[strlen (artist) - 1] == '\040') 
                        artist[strlen (artist) - 1] = '\000';
                  
                  strncpy (title, artist, strlen (artist));
                  strncat (title, " - ", 3);
                  strncat (title, song_name, strlen (song_name));

                  while (title[strlen (title) - 1] == '\040') 
                        title[strlen (title) - 1] = '\000';
                  
            }
            
            fclose(temp);
            titleptr = title;
      } else if (set.shortfilenames) {
            strcpy (title, filename);     /* so we can modify it without discression */
            titleptr = strrchr (title, PDELIM);

            if (!titleptr)
                  titleptr = title;
            else
                  titleptr = titleptr + 1;

            lastptr = strrchr (title, '.');
            if (lastptr)
                  *lastptr = '\0';
      } else {
            titleptr = filename;
      }

#ifndef _WIN32
      fcntl (sockfd, F_SETFL, 0);
#endif

      if (sockfd != -1) {
            if (set.use_icy) {
                  sock_write (sockfd, "GET /admin.cgi?pass=%s&mode=updinfo&song=%s HTTP/1.0\nHost:%s:%d\nUser-Agent: %s\n\n", set.password, url_encode (titleptr, &song), set.servername, set.port, VERSION);
            } else {
                  sock_write (sockfd, "GET /admin.cgi?pass=%s&mode=updinfo&mount=%s&song=%s&length=%ld HTTP/1.0\nHost:%s:%d\nUser-Agent: %s\n\n", set.password, url_encode (set.mount_name, &mount), url_encode (titleptr, &song), size, set.servername, set.port, VERSION);
                  if (mount)
                        free (mount);
            }
            sock_close (sockfd);
            if (song)
                  free (song);
      }
}

Generated by  Doxygen 1.6.0   Back to index