1 /*
2  * cdrom.c: This file handles all the CDROM routines, in BitchX
3  *
4  * Written by Tom Zickel
5  * a.k.a. IceBreak on the irc
6  *
7  * Copyright(c) 1996
8  * Modified Colten Edwards aka panasync.
9  *
10  */
11 #ifdef __linux__
12 #define CDROM_VERSION "0.02"
13 
14 #include "irc.h"
15 #include "struct.h"
16 #include "ircaux.h"
17 #define MODULE_CDROM
18 #include "cdrom.h"
19 #include "output.h"
20 #include "misc.h"
21 #include "vars.h"
22 
23 #include "module.h"
24 #define INIT_MODULE
25 #include "modval.h"
26 
27 #define cparse(s) convert_output_format(s, NULL, NULL)
28 
29 static int drive = 0;
30 
31 static char cdrom_prompt[]="%gC%Gd%gROM%w";
32 
33 #ifndef __FreeBSD__
34 static struct cdrom_tochdr hdr;
35 static struct cdrom_ti ti;
36 #else
37 static struct ioc_toc_header hdr;
38 #include <sys/disklabel.h>
39 #define MOUNT_CD9660 FS_ISO9660
40 #endif
41 
42 static struct cdrom_etocentry TocEntry[101];
43 
44 static char *cd_device = NULL;
45 
46 static int cd_init(char *);
47 
48 #ifndef __FreeBSD__
play_chunk(int start,int end)49 void play_chunk(int start, int end)
50 {
51 	struct cdrom_msf msf;
52 
53 	end--;
54 	if (start >= end)
55 		start = end-1;
56 
57 	msf.cdmsf_min0 = start / (60*75);
58 	msf.cdmsf_sec0 = (start % (60*75)) / 75;
59 	msf.cdmsf_frame0 = start % 75;
60 	msf.cdmsf_min1 = end / (60*75);
61 	msf.cdmsf_sec1 = (end % (60*75)) / 75;
62 	msf.cdmsf_frame1 = end % 75;
63 
64 	if (ioctl(drive, CDROMSTART))
65 	{
66 		put_it("%s: Could not start the cdrom",cparse(cdrom_prompt));
67 		return;
68 	}
69 	if (ioctl(drive, CDROMPLAYMSF, &msf))
70 	{
71 		put_it("%s: Could not play the track",cparse(cdrom_prompt));
72 		return;
73 	}
74 }
75 #endif
76 
check_cdrom_str(void)77 static int check_cdrom_str(void)
78 {
79 	if (cd_device)
80 		return 1;
81 	put_it("%s: /CDDEVICE  - The name of the CDROM device",cparse(cdrom_prompt));
82 	return 0;
83 }
84 
85 #if 0
86 static void lba2msf(int lba, unsigned char *msf)
87 {
88 #if !defined(CD_BLOCK_OFFSET)
89 #define CD_BLOCK_OFFSET CD_MSF_OFFSET
90 #endif
91 	lba += CD_BLOCK_OFFSET;
92 	msf[0] = lba / (CD_SECS*CD_FRAMES);
93 	lba %= CD_SECS*CD_FRAMES;
94 	msf[1] = lba / CD_FRAMES;
95 	msf[2] = lba % CD_FRAMES;
96 }
97 #endif
98 
cd_init(char * dev)99 int cd_init(char *dev)
100 {
101 int i, rc, pos;
102 
103 	if (!dev || ((drive = open(dev, O_RDONLY)) < 0))
104 		return (-1);
105 
106 	if ((rc = ioctl(drive, CDROMREADTOCHDR, &hdr)) == -1)
107 	{
108 		put_it("%s: can't get TocHeader (error %d).",cparse(cdrom_prompt), rc);
109 		return (-2);
110 	}
111 
112 #ifndef __FreeBSD__
113 	for (i=1;i<=hdr.cdth_trk1+1;i++)
114 	{
115 		if (i!=hdr.cdth_trk1+1)
116 			TocEntry[i].cdte_track = i;
117 		else
118 			TocEntry[i].cdte_track = CDROM_LEADOUT;
119 		TocEntry[i].cdte_format = CDROM_MSF;
120 		if (ioctl(drive,CDROMREADTOCENTRY,&TocEntry[i]))
121 			put_it("%s: Can't get TocEntry #%d",cparse(cdrom_prompt), i);
122 		else
123 		{
124 			TocEntry[i].avoid=TocEntry[i].cdte_ctrl & CDROM_DATA_TRACK ? 1 : 0;
125 			TocEntry[i].m_length = TocEntry[i].cdte_addr.msf.minute * 60 + TocEntry[i].cdte_addr.msf.second;
126 			TocEntry[i].m_start = TocEntry[i].m_length * 75 + TocEntry[i].cdte_addr.msf.frame;
127 		}
128 	}
129 
130 	pos = TocEntry[1].m_length;
131 
132 	for (i=1;i<=hdr.cdth_trk1+1;i++)
133 	{
134 		TocEntry[i].m_length = TocEntry[i+1].m_length - pos;
135 		pos = TocEntry[i+1].m_length;
136 		if (TocEntry[i].avoid)
137 			TocEntry[i].m_length = (TocEntry[i+1].m_start - TocEntry[i+1].m_start) *2;
138 	}
139 	return (hdr.cdth_trk1);
140 #else
141 	for (i = hdr.starting_track; i <= hdr.ending_track; i++)
142 	{
143 		TocEntry[i].avoid=0;
144 		TocEntry[i].m_start=1;
145 		TocEntry[i].m_length=1;
146 	}
147 	return (hdr.ending_track);
148 #endif
149 }
150 
check_mount(char * device)151 static int check_mount(char *device)
152 {
153 #ifndef __FreeBSD__
154 FILE *fp;
155 struct mntent *mnt;
156 
157 	if ((fp = setmntent(MOUNTED, "r")) == NULL)
158 		return 0;
159 
160 	while ((mnt = getmntent (fp)) != NULL)
161 	{
162 		if (!strcmp (mnt->mnt_type, "iso9660") && !strcmp (mnt->mnt_fsname, device))
163 		{
164 			endmntent(fp);
165 			return 0;
166 		}
167 	}
168 	endmntent (fp);
169 #else
170 struct statfs *mntinfo;
171 int i,count;
172 
173 	if (!(count = getmntinfo(&mntinfo,MNT_WAIT|MOUNT_CD9660)))
174 		return 0;
175 
176 	for(i = 0; i < count; i++)
177 		if (strstr(mntinfo[i].f_mntfromname,device) && !stricmp(mntinfo[i].f_dstypename, "iso9660"))
178 			return 0;
179 #endif
180 	return 1;
181 }
182 
BUILT_IN_DLL(set_cd_device)183 BUILT_IN_DLL(set_cd_device)
184 {
185 char *str;
186 int code;
187 	if (!(str = next_arg(args , &args)))
188 	{
189 		return;
190 	}
191 	if (drive)
192   		close(drive);
193 	if (!str || !check_mount(str))
194 	{
195 		put_it("%s: ERROR: CDROM is already mounted, please unmount, and try again",cparse(cdrom_prompt));
196 		new_free(&cd_device);
197 		return;
198 	}
199 
200 	if ((code = cd_init(str)) < 0)
201 	{
202 		put_it("%s: ERROR(%d): Could not initalize the CDROM, check if a disk is inside",cparse(cdrom_prompt), code);
203 		new_free(&cd_device);
204 		return;
205 	}
206 	put_it("%s: CDROM device is now set to - %s",cparse(cdrom_prompt),str);
207 	malloc_strcpy(&cd_device, str);
208 }
209 
BUILT_IN_DLL(cd_stop)210 BUILT_IN_DLL(cd_stop)
211 {
212 	if (!check_cdrom_str())
213 		return;
214 	if (!ioctl(drive, CDROMSTOP))
215 		put_it("%s: Stopped playing cdrom",cparse(cdrom_prompt));
216 	else
217 		put_it("%s: Stopped playing cdrom",cparse(cdrom_prompt));
218 }
219 
BUILT_IN_DLL(cd_eject)220 BUILT_IN_DLL(cd_eject)
221 {
222 	if (!check_cdrom_str() || !drive)
223 		return;
224 
225 	if (!ioctl(drive,CDROMEJECT))
226 		put_it("%s: ejected cdrom tray",cparse(cdrom_prompt));
227 	else
228 		put_it("%s: Stopped playing cdrom",cparse(cdrom_prompt));
229 	close(drive);
230 	drive=0;
231 }
232 
BUILT_IN_DLL(cd_play)233 BUILT_IN_DLL(cd_play)
234 {
235 
236 int tn;
237 char *trackn;
238 #ifndef __FreeBSD__
239 unsigned char first, last;
240 struct cdrom_tochdr tocHdr;
241 #else
242 struct ioc_play_track cdrom_play_args;
243 int result;
244 #endif
245 
246 	if (!check_cdrom_str() || !drive)
247 		return;
248 
249 	if (args && *args)
250 	{
251 		trackn=next_arg(args, &args);
252 		tn=atoi(trackn);
253 
254 #ifndef __FreeBSD__
255 		if ((ioctl(drive,CDROMREADTOCHDR,&tocHdr)))
256 		{
257 	        	put_it("%s: Couldnt get cdrom heder",cparse(cdrom_prompt));
258 	        	return;
259 		}
260 
261 	        first = tocHdr.cdth_trk0;
262 	        last = tocHdr.cdth_trk1;
263 	        ti.cdti_trk0=tn;
264 
265 	        if (ti.cdti_trk0<first)
266 	        	ti.cdti_trk0=first;
267 	        if (ti.cdti_trk0>last)
268 	        	ti.cdti_trk0=last;
269 
270 	        ti.cdti_ind0=0;
271 	        ti.cdti_trk1=last;
272 	        ti.cdti_ind1=0;
273 #else
274 		if (tn < hdr.starting_track)
275 			tn=hdr.starting_track;
276 		if (tn > hdr.ending_track)
277  			tn=hdr.ending_track;
278 #endif
279 	        if (TocEntry[tn].avoid==0)
280 	        {
281 #ifndef __FreeBSD__
282 			play_chunk(TocEntry[tn].m_start,TocEntry[last+1].m_start - 1);
283 #else
284 			cdrom_play_args.start_track=tn;
285 			cdrom_play_args.start_index=1;
286 			cdrom_play_args.end_track=hdr.ending_track;
287 			cdrom_play_args.end_index=1;
288 			(void)ioctl(drive,CDIOCPLAYTRACKS,&cdrom_play_args);
289 #endif
290 		        put_it("%s: Playing track number #%d",cparse(cdrom_prompt),tn);
291 	        }
292 	        else
293 	        	put_it("%s: Cannot play track #%d (Might be data track)",cparse(cdrom_prompt),tn);
294 	}
295         else
296 	        put_it("%s: Usage: /cdplay <track number>",cparse(cdrom_prompt));
297 
298 }
299 
BUILT_IN_DLL(cd_list)300 BUILT_IN_DLL(cd_list)
301 {
302 int i;
303 
304 	if (!check_cdrom_str())
305 		return;
306 #ifndef __FreeBSD__
307 	for (i=1;i<=hdr.cdth_trk1;i++)
308 #else
309 	for (i = hdr.starting_track; i < hdr.ending_track; i++)
310 #endif
311 	{
312 		put_it("%s: Track #%02d: %02d:%02d:%02d %02d:%02d:%02d",
313 			cparse(cdrom_prompt),
314 			i,
315 			TocEntry[i].m_length / (60*75),
316 			(TocEntry[i].m_length % (60*75)) / 75,
317 			TocEntry[i].m_length % 75,
318 			TocEntry[i].m_start / (60*75),
319 			(TocEntry[i].m_start % (60*75)) /75,
320 			TocEntry[i].m_start % 75
321 			);
322 	}
323 }
324 
BUILT_IN_DLL(cd_volume)325 BUILT_IN_DLL(cd_volume)
326 {
327 char *left, *right;
328 #ifndef __FreeBSD__
329 struct cdrom_volctrl volctrl;
330 #else
331 struct ioc_vol volctrl;
332 #endif
333 	if (!check_cdrom_str())
334 		return;
335 
336 	if (args && *args)
337 	{
338 		left=next_arg(args, &args);
339 		right=next_arg(args, &args);
340 		ioctl(drive, CDROMVOLREAD, &volctrl);
341 		if (left && *left)
342 #ifndef __FreeBSD__
343 			volctrl.channel0 = atoi(left);
344 #else
345 			volctrl.vol[0] = atoi(left);
346 #endif
347 		if (right && *right)
348 #ifndef __FreeBSD__
349 			volctrl.channel1 = atoi(right);
350 #else
351 			volctrl.vol[1] = atoi(right);
352 #endif
353 		if (ioctl(drive,CDROMVOLCTRL,&volctrl))
354 			put_it("%s: Couldnt set cdrom volume",cparse(cdrom_prompt));
355 		else
356 			put_it("%s: CDROM Volume is now <%d> <%d>",cparse(cdrom_prompt),
357 #ifndef __FreeBSD__
358 				volctrl.channel0,volctrl.channel1);
359 #else
360 				volctrl.vol[0],volctrl.vol[1]);
361 #endif
362 	}
363 	else
364 		put_it("%s: Usage: /cdvol <left> <right>",cparse(cdrom_prompt));
365 }
366 
BUILT_IN_DLL(cd_pause)367 BUILT_IN_DLL(cd_pause)
368 {
369 static int cpause = 0;
370 	if (!check_cdrom_str())
371 		return;
372 	if (ioctl(drive, !cpause?CDROMPAUSE:CDROMRESUME))
373 		put_it("%s: Couldnt pause/resume your cdrom",cparse(cdrom_prompt));
374 	else
375 		put_it("%s: %s",cparse(cdrom_prompt),!cpause?"Your cdrom has been paused":"Your cdrom has been resumed");
376 	cpause ^= 1;
377 }
378 
BUILT_IN_DLL(cd_help)379 BUILT_IN_DLL(cd_help)
380 {
381 	put_it("%s: CDPLAY            - Play a CDROM Track Number",cparse(cdrom_prompt));
382 	put_it("%s: CDSTOP            - Make the CDROM Stop playing",cparse(cdrom_prompt));
383 	put_it("%s: CDEJECT           - Eject the CDROM Tray",cparse(cdrom_prompt));
384 	put_it("%s: CDVOL             - Set's the CDROM Volume",cparse(cdrom_prompt));
385 	put_it("%s: CDLIST            - List of CDROM tracks",cparse(cdrom_prompt));
386 	put_it("%s: CDPAUSE           - Pause/resume the CDROM",cparse(cdrom_prompt));
387 }
388 
Cdrom_Version(IrcCommandDll ** interp)389 char *Cdrom_Version (IrcCommandDll **interp)
390 {
391 	return CDROM_VERSION;
392 }
393 
Cdrom_Init(IrcCommandDll ** interp,Function_ptr * global_table)394 int Cdrom_Init(IrcCommandDll **interp, Function_ptr *global_table)
395 {
396 char *name = "cdrom";
397 	initialize_module(name);
398 	add_module_proc(COMMAND_PROC, name, "cdstop", NULL, 0, 0, cd_stop, NULL);
399 	add_module_proc(COMMAND_PROC, name, "cdplay", NULL, 0, 0, cd_play, NULL);
400 	add_module_proc(COMMAND_PROC, name, "cdeject", NULL, 0, 0, cd_eject, NULL);
401 	add_module_proc(COMMAND_PROC, name, "cdlist", NULL, 0, 0, cd_list, NULL);
402 	add_module_proc(COMMAND_PROC, name, "cdhelp", NULL, 0, 0, cd_help, NULL);
403 	add_module_proc(COMMAND_PROC, name, "cdvolume", NULL, 0, 0, cd_volume, NULL);
404 	add_module_proc(COMMAND_PROC, name, "cdpause", NULL, 0, 0, cd_pause, NULL);
405 	add_module_proc(COMMAND_PROC, name, "cddevice", NULL, 0, 0, set_cd_device, NULL);
406 	put_it("%s: Module loaded and ready. /cddevice <dev> to start", cparse(cdrom_prompt));
407 	put_it("%s: /cdhelp for list of new commands.", cparse(cdrom_prompt));
408 	return 0;
409 }
410 #endif
411