1 /*
2 I would guess that this is the main file for Cmp3. When you do something,
3 this code cares. Of course, it is probably buggy so don't think it can
4 make your life meaningful just yet.
5 */
6
7 #define CMP3_NO_NEED_VARS /* Don't get extern globals from cmp3funcs.h */
8
9 #include "keydef.h"
10 #include "cmp3funcs.h"
11 #include "cmp3id3.h"
12
13 /*--- Global variables defined, let everyone else just extern them ---*/
14 LLIST list_left,
15 list_right;
16 WINDOW *pad_left, /* Pads on the inside */
17 *pad_right,
18 *pad_list,
19 *win_left, /* Outside windows */
20 *win_right,
21 *win_list;
22 int shmid, /* ID for shared memory block */
23 curwin; /* Which window has focus */
24 shmdata_t *shmptr; /* Pointer to shared memory block */
25 int noDirChange = 0; /* Don't change directory, passed on cmd line */
26 INI cmp3rc = NULL;
27 char directory[MAX_FULL];
28
29 /* The Code That Cares */
main(int argc,char ** argv)30 int main(int argc, char **argv)
31 {
32 int command;
33 int lastleftline = 0;
34 int lastrightline = 0;
35 char *init_dir = NULL;
36 char *home_dir = NULL;
37 char cmp3_config[4096];
38
39 if (argc > 1)
40 docmdline(argc, argv);
41 shm_init();
42
43 cmp3rc = ini_create();
44 home_dir = getenv("HOME");
45 strcpy (cmp3_config, home_dir);
46 strcat (cmp3_config, "/.cmp3rc");
47 if (ini_load(cmp3rc, cmp3_config) == INI_FAIL)
48 {
49 ini_destroy(cmp3rc);
50 cmp3rc = NULL;
51 }
52
53 curs_init();
54 initialize();
55 curwin = FOCUSED_LEFT;
56
57 wnoutrefresh(stdscr);
58 wnoutrefresh(win_left);
59 wrefresh(win_right);
60
61 if (noDirChange == 0) {
62 init_dir = ini_getValueString(cmp3rc,
63 "cmp3_options",
64 "initial_directory");
65 if (init_dir != NULL)
66 chdir(init_dir);
67 }
68 getcwd(directory, MAX_FULL);
69 init_dir = strdup(directory);
70 init_lists(directory, 0, 0);
71
72 refreshpads();
73
74 while (1) {
75 command=getch();
76 switch(command) {
77 /****************************************************************************
78 * Q (quit)
79 */
80 case CMP3_KEY_QUIT:
81 if ((ini_getValueBool(cmp3rc,
82 "cmp3_options",
83 "quit_confirm", 1) == 0) ||
84 (dialogbox("Really Quit?") == 1))
85 {
86 kill(shmptr->managpid,SIGINT);
87 free(init_dir);
88 enditall(1);
89 }
90 dialog_clean();
91 break;
92 /****************************************************************************
93 * Enter
94 */
95 case CMP3_KEY_ENTER:
96 if (curwin == FOCUSED_LEFT) {
97 char startatlast = 0;
98
99 if (dirchange(directory,
100 ((list_left_t*)ll_data(list_left))->name) == 0)
101 break;
102 if (strcmp(((list_left_t*)ll_data(list_left))->name,
103 "..") == 0)
104 {
105 startatlast = 1;
106 } else {
107 lastleftline = ll_curnum(list_left);
108 lastrightline = ll_curnum(list_right);
109 }
110 free_lists();
111 pads_clean();
112 if (startatlast == 1) {
113 init_lists(directory, lastleftline, lastrightline);
114 lastleftline = lastrightline = 0;
115 } else
116 init_lists(directory, 0, 0);
117 refreshpads();
118 } else {
119 char fullpath[MAX_FULL];
120 char *name;
121
122 if (ll_data(list_right) == NULL)
123 break;
124 name = ((list_right_t*) ll_data(list_right))->name;
125 strcpy(fullpath, directory);
126 strcat(fullpath, "/");
127 strcat(fullpath, name);
128 if (isPlaylist(fullpath))
129 readlist(fullpath);
130 else
131 pl_addentry(fullpath);
132 }
133 break;
134 /****************************************************************************
135 * Down
136 */
137 case CMP3_KEY_DOWN1: case CMP3_KEY_DOWN2:
138 {
139 LLIST thelist;
140 int *curline;
141
142 curline = getcurline(&thelist);
143
144 if (ll_curnum(thelist) == ll_total(thelist) - 1)
145 break;
146 ll_next(thelist);
147 ll_prnprev(thelist);
148 ll_prncur(thelist);
149
150 /* Scroll if needed */
151 if (ll_curnum(thelist) != ll_total(thelist))
152 if (*curline + (LINES-15) < ll_curnum(thelist))
153 if (ll_curnum(thelist) != ll_total(thelist) - 1)
154 *curline += 1;
155
156 refreshpad(curwin);
157 }
158 break;
159 /****************************************************************************
160 * Up
161 */
162 case CMP3_KEY_UP1: case CMP3_KEY_UP2:
163 {
164 LLIST thelist;
165 int *curline;
166
167 curline = getcurline(&thelist);
168
169 if (ll_curnum(thelist) == 0)
170 break;
171
172 if (*curline != 0) {
173 if (*curline >= ll_curnum(thelist)-1)
174 *curline -= 1;
175 if (*curline == ll_curnum(thelist))
176 *curline -= 1;
177 }
178
179 ll_prev(thelist);
180 ll_prncur(thelist);
181 ll_prnnext(thelist);
182
183 refreshpad(curwin);
184 }
185 break;
186 /****************************************************************************
187 * Page down or V
188 */
189 case CMP3_KEY_PGDN1: case CMP3_KEY_PGDN2:
190 {
191 int *curline,
192 i;
193 LLIST thewin;
194
195 curline = getcurline(&thewin);
196 if ((int)(ll_curnum(thewin) + LINES - 14) < (ll_total(thewin) - 1))
197 {
198 *curline += LINES-14;
199 if (*curline > (ll_total(thewin) - 14))
200 *curline = ll_total(thewin) - (LINES-13);
201 ll_next(thewin);
202 ll_prnprev(thewin);
203 for (i=0; i < LINES-15; i++)
204 if (ll_next(thewin) == NULL) {
205 *curline = ll_total(thewin) - LINES - 14;
206 ll_reset(thewin);
207 ll_prev(thewin);
208 break;
209 }
210 ll_prncur(thewin);
211 } else {
212 *curline = ll_total(thewin) - LINES + 13;
213 if (ll_curnum(thewin) != ll_total(thewin) - 1) {
214 i = curwin;
215 curwin = FOCUSED_NONE;
216 ll_prncur(thewin);
217 curwin = i;
218 ll_reset(thewin);
219 ll_prev(thewin);
220 ll_prncur(thewin);
221 }
222 }
223 refreshpad(curwin);
224 }
225 break;
226 /****************************************************************************
227 * Page up or U
228 */
229 case CMP3_KEY_PGUP1: case CMP3_KEY_PGUP2:
230 {
231 int *curline,
232 i;
233 LLIST thewin;
234
235 curline = getcurline(&thewin);
236 if ((int)(ll_curnum(thewin) - (LINES-14)) > 0 )
237 {
238 *curline -= LINES-14;
239 ll_prev(thewin);
240 ll_prnnext(thewin);
241 for (i=0; i < LINES-15; i++)
242 if (ll_prev(thewin) == NULL) {
243 *curline = 0;
244 ll_reset(thewin);
245 ll_next(thewin);
246 break;
247 }
248 ll_prncur(thewin);
249 } else {
250 *curline = 0;
251 if (ll_curnum(thewin) != 0) {
252 i = curwin;
253 curwin = FOCUSED_NONE;
254 ll_prncur(thewin);
255 curwin = i;
256 ll_reset(thewin);
257 ll_next(thewin);
258 ll_prncur(thewin);
259 }
260 }
261 refreshpad(curwin);
262 }
263 break;
264 /****************************************************************************
265 * Left, Right or Tab
266 */
267 case CMP3_KEY_SWITCH1:
268 case CMP3_KEY_SWITCH2:
269 case CMP3_KEY_SWITCH3:
270 curwin = switchwin(curwin);
271 break;
272 /****************************************************************************
273 * Volume control (+ and -)
274 */
275 case CMP3_KEY_VOLUP1: case CMP3_KEY_VOLUP2:
276 volup();
277 break;
278 case CMP3_KEY_VOLDWN1: case CMP3_KEY_VOLDWN2:
279 voldown();
280 break;
281 /****************************************************************************
282 * Delete
283 */
284 case CMP3_KEY_DELETE:
285 if (curwin == FOCUSED_LEFT)
286 break;
287 if (ll_data(list_right) == NULL)
288 break;
289 if ((ini_getValueBool(cmp3rc,
290 "cmp3_options",
291 "delete_confirm", 1) == 0) ||
292 (dialogbox("Delete this file?") == 1))
293 {
294 char fullpath[MAX_FULL];
295
296 strcpy(fullpath, directory);
297 strcat(fullpath,"/");
298 strcat(fullpath,((list_right_t*)ll_data(list_right))->name);
299 remove(fullpath);
300 /* XXX Ick */
301 pads_clean();
302 free_lists();
303 init_lists(directory, 0, 0);
304 }
305 dialog_clean();
306 break;
307 /****************************************************************************
308 * L (list mode)
309 * blends into refresh
310 */
311 case CMP3_KEY_LISTMODE:
312 {
313 int curwinbackup;
314
315 curwinbackup = curwin;
316 curwin = FOCUSED_LIST;
317 dolist();
318 curwin = curwinbackup;
319 }
320 /****************************************************************************
321 * R (refresh screen)
322 */
323 case CMP3_KEY_REFRESH:
324 if (command == CMP3_KEY_REFRESH) {
325 pads_clean();
326 free_lists();
327 init_lists(directory, 0, 0);
328 }
329 after_list();
330 break;
331 /****************************************************************************
332 * P (pause song)
333 */
334 case CMP3_KEY_PAUSE:
335 /* XXX - find out if bufferring and pause all pids */
336 if (shmptr->pid) {
337 if (!shmptr->pause) {
338 shmptr->pause=1;
339 kill(shmptr->pid,SIGSTOP);
340 } else {
341 shmptr->pause=0;
342 kill(shmptr->pid,SIGCONT);
343 }
344 }
345 break;
346 /****************************************************************************
347 * F5 (restart song) - drops into kill
348 */
349 case CMP3_KEY_RESTART:
350 if (!shmptr->pid)
351 break;
352 pl_dupfirst();
353 if (shmptr->repeat == 1)
354 shmptr->listlen -= 1;
355 /****************************************************************************
356 * K (kill song)
357 */
358 case CMP3_KEY_KILL1: case CMP3_KEY_KILL2:
359 if (shmptr->pid)
360 kill(shmptr->pid,SIGKILL);
361 shmptr->pause=0;
362 break;
363 /****************************************************************************
364 * H (home directory)
365 * A (ass directory) - if specified
366 */
367 #ifdef ASS_LOC
368 case CMP3_KEY_CHDIRASS:
369 #endif /* ASS_LOC */
370 case CMP3_KEY_CHDIR:
371 case CMP3_KEY_CHDIRHOME:
372 if (command == CMP3_KEY_CHDIRHOME)
373 strcpy(directory, init_dir);
374 else if (command == CMP3_KEY_CHDIR)
375 {
376 char dirnamebuffer[MAX_FULL];
377
378 memset(dirnamebuffer, ' ', MAX_FULL);
379 memcpy(dirnamebuffer, directory, strlen(directory));
380 if (inputbox("Change Directory?", dirnamebuffer, MAX_FULL)
381 == 0)
382 {
383 dialog_clean();
384 break;
385 }
386 dialog_clean();
387 strcpy(directory, dirnamebuffer);
388 }
389 #ifdef ASS_LOC
390 else
391 strcpy(directory, ASS_LOC);
392 #endif /* ASS_LOC */
393 pads_clean();
394 free_lists();
395 init_lists(directory, 0, 0);
396 lastleftline = lastrightline = 0;
397 refreshpads();
398 break;
399 /****************************************************************************
400 * d (add directory)
401 */
402 case CMP3_KEY_ADDDIR: {
403 list_right_t* file;
404
405 if ((ini_getValueBool(cmp3rc,
406 "cmp3_options",
407 "other_confirm", 1) == 0) ||
408 (dialogbox("Add Entire Directory?") == 1))
409 {
410 ll_reset(list_right);
411 while ((file = ll_next(list_right)) != NULL)
412 if (!isPlaylist(file->name)) {
413 char fullpath[MAX_FULL];
414
415 strcpy(fullpath, directory);
416 strcat(fullpath, "/");
417 strcat(fullpath, file->name);
418 pl_addentry(fullpath);
419 }
420 ll_next(list_right);
421 }
422 dialog_clean();
423 }
424 break;
425 /****************************************************************************
426 * D (recursively add directory)
427 */
428 case CMP3_KEY_RECURADDIR:
429 if ((ini_getValueBool(cmp3rc,
430 "cmp3_options",
431 "other_confirm", 1) == 0) ||
432 (dialogbox("Recurse Directory?") == 1))
433 {
434 recursdir(directory, RECURS_DEPTH);
435 }
436 dialog_clean();
437 break;
438 /****************************************************************************
439 * C (clear playlist)
440 */
441 case CMP3_KEY_CLEARPL:
442 if (shmptr->listlen < 2)
443 break;
444 if ((ini_getValueBool(cmp3rc,
445 "cmp3_options",
446 "other_confirm", 1) == 0) ||
447 (dialogbox("Clear Entire Playlist?") == 1))
448 {
449 if (shmptr->pid) {
450 pl_clear();
451 }
452 }
453 dialog_clean();
454 break;
455 /****************************************************************************
456 * S (suspend mode)
457 */
458 case CMP3_KEY_SUSPEND:
459 if (!(shmptr->pid))
460 break;
461 if ((ini_getValueBool(cmp3rc,
462 "cmp3_options",
463 "suspend_confirm", 1) == 0) ||
464 (dialogbox("Do you want to suspend?") == 1))
465 {
466 enditall(1);
467 }
468 dialog_clean();
469 break;
470 /****************************************************************************
471 * W (write playlist)
472 */
473 case CMP3_KEY_WRITEPL:
474 {
475 char filenamebuffer[MAX_FULL];
476 if (shmptr->listlen < 2)
477 break;
478 memset(filenamebuffer, ' ', MAX_FULL);
479 memcpy(filenamebuffer, DEFAULT_ASSFILE, strlen(DEFAULT_ASSFILE));
480 if (inputbox("Save List?", filenamebuffer, MAX_FULL) == 1)
481 {
482 #ifdef ASS_LOC
483 char temp[MAX_FULL];
484 if (filenamebuffer[0] != '/')
485 {
486 strcpy(temp,ASS_LOC);
487 strcat(temp,"/");
488 strcat(temp, filenamebuffer);
489 writelist(temp);
490 } else {
491 writelist(filenamebuffer);
492 }
493 #else /* ASS_LOC */
494 writelist(filenamebuffer);
495 #endif /* ASS_LOC */
496 }
497 dialog_clean();
498 }
499 break;
500 /****************************************************************************
501 * Repeat Mode
502 */
503 case CMP3_KEY_REPEAT:
504 if (shmptr->repeat == 0)
505 {
506 mvprintw(LINES - 2, 3, "R");
507 shmptr->repeat = 1;
508 } else {
509 mvprintw(LINES - 2, 3, " ");
510 shmptr->repeat = 0;
511 }
512 break;
513 /****************************************************************************
514 * F1 (help)
515 */
516 case CMP3_KEY_HELP:
517 showhelp();
518 after_list();
519 break;
520 /****************************************************************************
521 * My personal cd changing code
522 * "disk" is a perl script that changes my cd changer, so this probably
523 * won't do you much good.
524 */
525 #ifdef MY_CD
526 case '1': case '2': case '3': case '4':
527 {
528 char temp[] = "disk ! >& /dev/null";
529
530 temp[5] = command;
531 system(temp);
532 }
533 break;
534 #endif /* MY_CD */
535 /****************************************************************************
536 * Default - unpause if paused
537 */
538 default:
539 if (shmptr->pause) {
540 kill(shmptr->pid,SIGCONT);
541 shmptr->pause=0;
542 }
543 /* Helpful to find out what number for a key */
544 /*
545 attron(A_BLINK);
546 attron(A_REVERSE);
547 mvprintw(2,COLS/3,"Hit q to quit you idiot: %d entered",command);
548 attroff(A_BLINK);
549 attroff(A_REVERSE);
550 */
551 break;
552 } /* switch */
553 } /* while */
554 enditall(1);
555 return(0);
556 }
557
558 /****************************************************************************
559 * Spawn a manager process
560 * Returns: nothing
561 ****************************************************************************/
spawn_manager()562 int spawn_manager()
563 {
564 int manapid;
565
566 manapid=fork();
567 if (manapid == -1) {
568 perror("Can't fork\n");
569 enditall(0);
570 }
571 if (!manapid) {
572 manageit();
573 exit(0);
574 }
575 return(manapid);
576 }
577
578 /****************************************************************************
579 * Initialize shared memory segment
580 * If shared memory segment exists already, use it.. otherwise spawn
581 * a manager process. Shared memory stays in block pointed by shmptr
582 * Returns: nothing
583 ****************************************************************************/
shm_init()584 void shm_init()
585 {
586 char *home;
587 int proccheck=1;
588 struct shmid_ds shminfo;
589 static int initialized = 0;
590
591 if (initialized != 0)
592 return;
593
594 home = getenv("HOME");
595 shmid = shmget(ftok(home,69),
596 sizeof(shmdata_t),
597 0600 | IPC_CREAT | IPC_EXCL);
598
599 /* if SOMETHING is already running (what?) */
600 if ((shmid == -1) && (errno == EEXIST)) {
601 shmid=shmget(ftok(home,69),
602 sizeof(shmdata_t),
603 0600 | IPC_CREAT);
604 } else {
605 proccheck = 0;
606 spawn_manager();
607 }
608
609 shmptr = (shmdata_t*) shmat(shmid,NULL,0);
610 if (shmptr == (shmdata_t*) -1) {
611 perror("can't attach shared memory");
612 enditall(69);
613 }
614
615 /* Check if any manager process is attached to it */
616 if (proccheck && ((shmctl(shmid, IPC_STAT, &shminfo) == 0))) {
617 if (shminfo.shm_nattch < 2)
618 spawn_manager();
619 }
620
621 /* why? */
622 while (shmptr->managpid == 0)
623 printf("\r");
624
625 initialized = 1;
626 return;
627 }
628
629 /****************************************************************************
630 * Check command line inserts for ass files or commands
631 * Returns: nothing
632 ****************************************************************************/
docmdline(int argc,char ** argv)633 void docmdline(int argc, char **argv)
634 {
635 if (!Strcmp(argv[1], "version")) {
636 printf("Cmp3 %s - %s\n\n", CMP3_VER, CMP3_COOLLINE);
637 printf("mpg123 located at %s\n", EXEC_LOC);
638 printf("ogg123 located at %s\n", OGG_LOC);
639 #ifdef ASS_LOC
640 printf("Ass repository located at %s\n", ASS_LOC);
641 #endif /* ASS_LOC */
642 enditall(69);
643 }
644 #ifdef ASS_LOC
645 if (!Strcmp(argv[1],"list")) {
646 char temp[MAX_WIDTH];
647
648 sprintf(temp,"ls %s/*.ass",ASS_LOC);
649 system(temp);
650 enditall(69);
651 }
652 #endif /* ASS_LOC */
653
654 shm_init();
655 if ((!Strcmp(argv[1],"skip")) || (!Strcmp(argv[1], "next"))) {
656 if (shmptr->pid)
657 kill(shmptr->pid,SIGKILL);
658 enditall(69);
659 }
660 if (!Strcmp(argv[1],"quit")) {
661 if (shmptr->managpid)
662 kill(shmptr->managpid,SIGINT);
663 enditall(69);
664 }
665 if (!Strcmp(argv[1],"song")) {
666 if (shmptr->pid) {
667 if (shmptr->pause == 1) {
668 printf("Paused: ");
669 } else {
670 printf("Playing: ");
671 }
672 printf("%s\n", shmptr->plhead);
673 } else {
674 printf("No song playing\n");
675 }
676 enditall(69);
677 }
678 if (!Strcmp(argv[1],"pause")) {
679 if (shmptr->pid) {
680 if (shmptr->pause) {
681 shmptr->pause=0;
682 kill(shmptr->pid,SIGCONT);
683 } else {
684 shmptr->pause=1;
685 kill(shmptr->pid,SIGSTOP);
686 }
687 }
688 enditall(69);
689 }
690 if (!Strcmp(argv[1], "restart")) {
691 if (shmptr->pid) {
692 pl_dupfirst();
693 kill(shmptr->pid, SIGINT);
694 if (shmptr->repeat == 1)
695 shmptr->listlen -= 1;
696 }
697 enditall(69);
698 }
699 if (!Strcmp(argv[1], "info")) {
700 if (shmptr->listlen > 0) {
701 id3info_t songinfo;
702
703 if (readid3(&songinfo, shmptr->plhead) == 0) {
704 printf("Filename: %s\n", shmptr->plhead);
705 printf("Name: %.30s\n", songinfo.name);
706 printf("Artist: %.30s\n", songinfo.artist);
707 printf("Album: %.4s %.30s\n", songinfo.year, songinfo.album);
708 printf("Comment: %.30s\n", songinfo.comment);
709 printf("Genre: %s\n",
710 songinfo.genre ? "Unlisted" : id3genre[(int) songinfo.genre]);
711 } else {
712 printf("No id3 tag information for %s\n", shmptr->plhead);
713 }
714 }
715 enditall(69);
716 }
717 if ((!Strcmp(argv[1], "playlist")) || (!Strcmp(argv[1], "songs"))) {
718 if (shmptr->listlen > 0) {
719 int i;
720 char *ptr;
721
722 printf("%s -> %s\n", shmptr->pause ? "Paused " : "Playing",
723 shmptr->plhead);
724 ptr = shmptr->plhead + strlen(shmptr->plhead) + 1;
725 for (i = 1; i < shmptr->listlen; i++) {
726 printf(" %s\n", ptr);
727 ptr += strlen(ptr) + 1;
728 }
729 }
730 enditall(69);
731 }
732 if (!Strcmp(argv[1], "adddir")) {
733 char directory[MAX_FULL];
734
735 if (argc > 2)
736 chdir(argv[2]);
737 getcwd(directory, MAX_FULL);
738 recursdir(directory, RECURS_DEPTH);
739 enditall(69);
740 }
741 if (!Strcmp(argv[1],"random")) {
742 if (shmptr->pid)
743 pl_randomize(1);
744 enditall(69);
745 }
746 if (!Strcmp(argv[1]+(strlen(argv[1])-4),".mp3")) {
747 if (argv[1][0] == '/')
748 pl_addentry(argv[1]);
749 else {
750 char fullpath[MAX_FULL];
751
752 getcwd(fullpath, MAX_FULL);
753 strcat(fullpath, "/");
754 strcat(fullpath, argv[1]);
755 pl_addentry(fullpath);
756 }
757 enditall(69);
758 }
759 if (isPlaylist(argv[1])) {
760 readlist(argv[1]);
761 enditall(69);
762 }
763 if (argv[1][0] == '/') {
764 if (isdir("", argv[1]) == 1)
765 {
766 chdir(argv[1]);
767 noDirChange = 1;
768 return;
769 }
770 } else {
771 if (isdir(".", argv[1]) == 1)
772 {
773 chdir(argv[1]);
774 noDirChange = 1;
775 return;
776 }
777 }
778 printf("Cmp3 %s - %s\n\n", CMP3_VER, CMP3_COOLLINE);
779 printf(
780 "Usage: cmp3 [file.ass] [directory] [pause] [skip] [info] [quit]\n"
781 " [random] [restart] [adddir directory] [song] [playlist]\n"
782 " [version]");
783 #ifdef ASS_LOC
784 printf(" [list]");
785 #endif /* ASS_LOC */
786 printf ("\n");
787 if (!shmptr->pid)
788 kill(shmptr->managpid,SIGINT);
789 enditall(69);
790 return;
791 }
792
793 /****************************************************************************
794 * Get curent line out of the info area and set thelist to point to
795 * the list that is currently focused
796 * Returns: pointer to curline number
797 ****************************************************************************/
getcurline(void ** thelist)798 int *getcurline(void **thelist)
799 {
800 if (curwin == FOCUSED_LEFT) {
801 *thelist = list_left;
802 return( &(((info_left_t*) ll_info(list_left, NULL))->line) );
803 } else {
804 *thelist = list_right;
805 return( &(((info_right_t*) ll_info(list_right, NULL))->line) );
806 }
807 }
808
809 /* EOF */
810