/*
 * Copyright (c) 1994,1995  Dimitrios P. Bouras and William K. W. Cheung
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
 * Except as contained in this notice, the name of the X Consortium shall not be
 * used in advertising or otherwise to promote the sale, use or other dealings
 * in this Software without prior written authorization from the X Consortium.
 * 
 * Derived from the MIT X11R5 xbiff, written by Jim Fulton, which is
 * copyrighted (c) 1988 X Consortium.
 *
 * Mailbox XPM additions-modifications:  Dimitrios P. Bouras
 * Audio support and XPM icon animation: William K. W. Cheung

 * Derived from xmailbox by Dimitrios P. Bouras and William K. W. Cheung
 * as well as volume by Sam Lantinga. The above copyright notice is
 * from Dimitros and William's file Mailbox.c in the xmailbox application.
 * modified and integrated into Coolmail: Randall K. Sharpe */

#include <sys/stat.h>			/* for stat() ** needs types.h ***/
#include <sys/signal.h>			/* for signal() */
#include <stdio.h>				/* for printing error messages */
#include <pwd.h>				/* for getting username */
#include <stdlib.h>				/* for getenv() */
#include <string.h>

#include <sys/file.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>

extern int cool_vol;
extern char *sndfile;

/* I am only doing sun audio -- RKS */

/* Adapted from <multimedia/audio_filehdr.h> */

typedef unsigned 	u_32;	/* we assume sizeof(unsigned) = 4 */

typedef struct {
	u_32		magic;		/* magic number */
	u_32		hdr_size;	/* size of this header */
	u_32		data_size;	/* length of data (optional) */
	u_32		encoding;	/* data encoding format */
	u_32		sample_rate;	/* samples per second */
	u_32		channels;	/* number of interleaved channels */
} Audio_filehdr;

#ifdef linux
#include <linux/soundcard.h>

#define DEV_MIXER		"/dev/mixer"
#define MAX_VOLUME		100
#define MIN_VOLUME		1
#define RIGHT			0x01
#define LEFT			0x02

typedef struct stereovolume
{
	unsigned char left;
	unsigned char right;
	unsigned char pad[2];
} StereoVolume;

void setvolume(int which, unsigned char setting, StereoVolume *volptr)
{
	if ( setting < MIN_VOLUME )
		setting=MIN_VOLUME;
	if ( setting > MAX_VOLUME )
		setting=MAX_VOLUME;

	if ( which&RIGHT )
		volptr->right=setting;
	if ( which&LEFT )
		volptr->left=setting;
}
#else
#include <sun/audioio.h>
#endif

#ifndef min
#define min(x,y)	((x) < (y)? (x): (y))
#endif

#define CLOSE_FD(afd)	{ if (afd > -1) close(afd); afd = -1; }

#ifdef linux
#define INIT_FD	{ audiofd = filefd = mixer_fd = -1; }
#define END_FD	{ CLOSE_FD(audiofd); CLOSE_FD(filefd); CLOSE_FD(mixer_fd); return; }
#else
#define INIT_FD	{ audiofd = filefd = 0; }
#define END_FD	{ CLOSE_FD(audiofd); CLOSE_FD(filefd); return; }
#endif


void audio_beep (void)
{
	int		audiofd, filefd;
	int		rn, wn, len;
	unsigned char	buf[256];
	Audio_filehdr	*au_hdr;

#ifdef linux
	StereoVolume origVol, volume;
	int				mixer_fd;
#else
	audio_info_t 	ais;
	int				origVol;	
#endif

	INIT_FD;
	audiofd = open( "/dev/audio", O_WRONLY | O_NDELAY ); 
	if (audiofd < 0) {
		fprintf(stderr, "%s: Problem opening /dev/audio.\n",
				"Coolmail");
		END_FD;
	}
#ifdef linux
	if ( (mixer_fd=open(DEV_MIXER, O_RDWR, 0)) < 0 ) {
		fprintf(stderr, "Can't open %s: ", DEV_MIXER);
		END_FD;
	}

	if ( ioctl(mixer_fd, MIXER_READ(SOUND_MIXER_VOLUME), &origVol) < 0 ) {
		perror("Can't obtain current volume settings");
		END_FD;
	}

	setvolume(LEFT|RIGHT, cool_vol, &volume);

	if ( ioctl(mixer_fd, MIXER_WRITE(SOUND_MIXER_VOLUME), &volume) < 0 ) {

		fprintf(stderr, "Can't set current volume settings");
		END_FD;
	}

#else
	if( ioctl( audiofd, AUDIO_GETINFO, &ais ) ) {
		fprintf(stderr, "%s: Problem retrieving /dev/audio info.\n",
				"Coolmail");
		END_FD;
	}
	origVol = ais.play.gain;
	ais.play.gain = cool_vol;
	if( ioctl( audiofd, AUDIO_SETINFO, &ais ) ) {
                fprintf(stderr, "Coolmail: Error %d returned from ioctl.\n",
                        errno);
		fprintf(stderr, "%s: Problem setting /dev/audio info.\n",
				"Coolmail");
		END_FD;
	}
#endif
	filefd = open(sndfile, O_RDONLY);
	if (filefd < 0) {
		fprintf(stderr, "%s: Couldn't play file \"%s\"\n", 
				"Coolmail", sndfile);
		END_FD;
	}

	/* Read in the audio header */
	rn = read(filefd, buf, sizeof(Audio_filehdr)); 

	if (rn > 0 && strncmp(buf, ".snd", 4) != 0) {
		fprintf(stderr, "%s: Invalid audio file format.\n",
				"Coolmail");
		END_FD;
	}

	/* Strip the header */
	au_hdr = (Audio_filehdr *)buf;
#ifdef linux
	rn = ntohl(au_hdr->hdr_size) - sizeof(Audio_filehdr); 	
#else
	rn = au_hdr->hdr_size - sizeof(Audio_filehdr);
#endif
	for( ; rn > 0; ) {
		len = min(rn, sizeof(buf));
		len = read(filefd, buf, len); 
		rn -= len;	
	}

	while(1) {
		rn = read(filefd, buf, sizeof(buf));
		if (rn < 0) {
			fprintf(stderr, "%s: Error reading from file \"%s\"\n", 
					"Coolmail", sndfile);
			END_FD;
		}
		if (rn == 0)
			break;
		while(1) {
			wn = write(audiofd, buf, rn);
			if ( wn < 0 ) {
				fprintf(stderr, "%s: Error writing to /dev/audio.\n", 
						"Coolmail");
				END_FD;
			}
			if ( wn != 0 )
				break;
			usleep(1000);
		}
	}
#ifdef linux
	CLOSE_FD(audiofd);

	if ( ioctl(mixer_fd, MIXER_WRITE(SOUND_MIXER_VOLUME), &origVol) < 0 ) {
		fprintf(stderr, "Can't reset volume settings");
	}

	CLOSE_FD(mixer_fd);

#else
	ais.play.gain = origVol;
	if( ioctl( audiofd, AUDIO_SETINFO, &ais ) ) {
		fprintf(stderr, "%s: Problem setting /dev/audio info.\n",
				"Coolmail");
	}
#endif
	END_FD;

    return;
}

