From owner-freebsd-multimedia@FreeBSD.ORG Sat Mar 27 11:44:56 2004 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 038C116A4CE for ; Sat, 27 Mar 2004 11:44:56 -0800 (PST) Received: from feith1.FEITH.COM (feith1.FEITH.COM [192.251.93.1]) by mx1.FreeBSD.org (Postfix) with ESMTP id 89A7943D39 for ; Sat, 27 Mar 2004 11:44:55 -0800 (PST) (envelope-from john@feith.com) Received: from jwlab.FEITH.COM (jwlab.FEITH.COM [192.251.93.16]) by feith1.FEITH.COM (8.12.10+Sun/8.12.9) with ESMTP id i2RJiqkQ002968; Sat, 27 Mar 2004 14:44:52 -0500 (EST) Received: (from john@localhost) by jwlab.FEITH.COM (8.11.7p1+Sun/8.11.7) id i2RJigT06373; Sat, 27 Mar 2004 14:44:42 -0500 (EST) Date: Sat, 27 Mar 2004 14:44:42 -0500 (EST) From: John Wehle Message-Id: <200403271944.i2RJigT06373@jwlab.FEITH.COM> To: christoph.schnauss@berlin.de Content-Type: text X-Scanned-By: MIMEDefang 2.39 X-Archived: cashew.FEITH.COM cc: fernando@secret.org cc: multimedia@freebsd.org Subject: Re: Hauppauge WinTV PVR 250 for FreeBSD 5.2 X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 27 Mar 2004 19:44:56 -0000 >> I'm using a web based VCR application I wrote in C and PHP to record >> programs. It's not whizzy, however it gets the job done. If you're >> interested I can send you a copy. > > I'm interested, and guess, any others too ;-) Enclosed. -- John -------------------------8<----------------------------8<-------------------- # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # tvrec # tvrec/README # tvrec/etc # tvrec/etc/tvrec.sh # tvrec/conf # tvrec/conf/config.php # tvrec/src # tvrec/src/Makefile # tvrec/src/tvrecd.c # tvrec/data # tvrec/htdocs # tvrec/htdocs/scheddeli.php # tvrec/htdocs/sched.php # tvrec/htdocs/schedaddi.php # echo c - tvrec mkdir -p tvrec > /dev/null 2>&1 echo x - tvrec/README sed 's/^X//' >tvrec/README << 'END-of-tvrec/README' X1) Verify the web environment. The VCR application is known X to work in an environment which has: X X Apache (www.apache.org) 1.3.29 X PHP (www.php.net) 4.3.4 X MM (www.ossp.org/pkg/lib/mm/) 1.3.0 X Berkley DB (www.sleepycat.com) 4.1.25 patchlevel 1 X X where PHP is configured with: X X ./configure --with-apxs=/usr/local/apache/bin/apxs --enable-dba \ X --with-mm --with-db4=/usr/local/BerkeleyDB --with-flatfile X X2) Install the web components. X X mkdir /home/www/tvrec X find conf data htdocs -depth -print | cpio -pvumd /home/www/tvrec X chown -R root:www /home/www/tvrec X chown -R nobody:www /home/www/tvrec/data X X3) Configure the web server by adding: X X Alias /tvrec /home/www/tvrec/htdocs/ X Alias /tv-rec /home/www/tvrec/htdocs/sched.php X X X AllowOverride None X Options None X Order deny,allow X Deny from all X Allow from xxx.xxx.xxx.xxx/xx X X X to httpd.conf and restarting the server: X X /usr/local/apache/bin/apachectl graceful X X4) Install the daemon. X X cd src X make X cp tvrecd /usr/local/sbin X chmod 700 /usr/local/sbin/tvrecd X chown root:wheel /usr/local/sbin/tvrecd X X5) Edit the start / stop script as necessary to set X the directories for the schedule database and X video recordings. X X6) Install the start / stop script. X X cd etc X cp tvrec.sh /usr/local/etc/rc.d X chmod 744 /usr/local/etc/rc.d/tvrec.sh X chown root:sys /usr/local/etc/rc.d/tvrec.sh X X7) Start the daemon. X X /usr/local/etc/rc.d/tvrec.sh start X X8) Goto http:/localhost/tv-rec and enter a program X to record. X X9) Enjoy! END-of-tvrec/README echo c - tvrec/etc mkdir -p tvrec/etc > /dev/null 2>&1 echo x - tvrec/etc/tvrec.sh sed 's/^X//' >tvrec/etc/tvrec.sh << 'END-of-tvrec/etc/tvrec.sh' X#!/bin/sh X# X# This file should have uid root, gid sys and chmod 744 X# X X XPATH=$PATH:/usr/local/bin Xexport PATH X Xif [ ! -d /usr/local/bin ] Xthen # /usr not mounted X exit Xfi X Xkillproc() { # kill the named process(es) X pid=`/bin/ps -ax | X /usr/bin/grep -w $1 | X /usr/bin/sed -e 's/^ *//' -e 's/ .*//'` X [ "$pid" != "" ] && kill $pid X} X X# Start/stop processes required for TVrecd server X Xcase "$1" in X X'start') X echo "Starting TVrecd" X /usr/local/sbin/tvrecd -f /home/www/tvrec/data/schedule.db -o /home/multimedia/video/tv X ;; X'stop') X echo "Stopping TVrecd" X killproc tvrecd X ;; X'restart') X $0 stop X $0 start X ;; X*) X echo "Usage: /usr/local/etc/rc.d/tvrec.sh { start | stop }" X ;; Xesac X Xexit 0 END-of-tvrec/etc/tvrec.sh echo c - tvrec/conf mkdir -p tvrec/conf > /dev/null 2>&1 echo x - tvrec/conf/config.php sed 's/^X//' >tvrec/conf/config.php << 'END-of-tvrec/conf/config.php' X END-of-tvrec/conf/config.php echo c - tvrec/src mkdir -p tvrec/src > /dev/null 2>&1 echo x - tvrec/src/Makefile sed 's/^X//' >tvrec/src/Makefile << 'END-of-tvrec/src/Makefile' XCFLAGS = -g -O2 XCPPFLAGS = -I/usr/local/BerkeleyDB/include -I/usr/local/include XLIBS = -L/usr/local/BerkeleyDB/lib -R/usr/local/BerkeleyDB/lib -ldb X Xall: tvrecd X Xtvrecd: tvrecd.c X $(CC) $(CFLAGS) $(CPPFLAGS) -o tvrecd tvrecd.c $(LIBS) X X Xclean: X rm -f *.o X X Xclobber: X rm -f *.o X rm -f tvrecd END-of-tvrec/src/Makefile echo x - tvrec/src/tvrecd.c sed 's/^X//' >tvrec/src/tvrecd.c << 'END-of-tvrec/src/tvrecd.c' X/* X * Copyright (c) 2003 X * John Wehle . All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This product includes software developed by John Wehle. X * 4. The name of the author may not be used to endorse or promote products X * derived from this software without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN X * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X */ X X/* X * Daemon for recording TV shows based on a schedule stored X * in a Berkeley DB. X */ X X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X X#include "db.h" X X X#define CHECK_DATABASE_SECONDS 20 X#define DATABASE "schedule.db" X#define LOGFILE "/var/log/tvrecd.log" X X Xstatic const char *MyName = "tvrecd"; X Xstatic int daimon = 0; Xstatic volatile int shutdown_server = 0; Xstatic sigset_t block_signal_set; X X Xenum quality { vcd_qt, svcd_qt, dvd_qt }; Xenum repeat { none_rpt, daily_rpt, weekly_rpt }; X Xstruct program { X unsigned int channel; X enum quality quality; X time_t start; X time_t stop; X enum repeat repeat; X char *name; X struct program *next; X }; X X Xstatic void Xcatch_signal () X { X X shutdown_server = 1; X } X X Xstatic void Xdaemonize() X { X X#ifdef SIGTSTP X signal(SIGTSTP, SIG_IGN); X#endif X#ifdef SIGTTIN X signal(SIGTTIN, SIG_IGN); X#endif X#ifdef SIGTTOU X signal(SIGTTOU, SIG_IGN); X#endif X X switch (fork ()) { X case 0: X break; X X case -1: X fprintf (stderr, "%s: daemonize -- fork failed.", MyName); X perror (MyName); X exit (1); X /* NOTREACHED */ X break; X X default: X exit (0); X /* NOTREACHED */ X break; X } X X setsid(); X X close (0); X close (1); X close (2); X X (void)open ("/dev/null", O_RDWR); X (void)open ("/dev/null", O_RDWR); X (void)open (LOGFILE, O_WRONLY | O_APPEND | O_CREAT, 0644); X X daimon = 1; X } X X Xstatic void Xerrmsg (const char *fmt, ...) X { X char time_stamp[256]; X struct tm *tmp; X time_t now; X va_list args; X X if (! daimon) { X fprintf (stderr, "%s: ", MyName); X X va_start (args, fmt); X vfprintf (stderr, fmt, args); X va_end (args); X X if (! strchr (fmt, '\n')) X fputc ('\n', stderr); X X fflush (stderr); X return; X } X X if (flock (fileno (stderr), LOCK_EX) == -1) { X fprintf (stderr, "%s: errmsg -- can't lock log.\n", MyName); X perror (MyName); X return; X } X X time (&now); X X if ( !(tmp = localtime (&now)) ) { X fprintf (stderr, "%s: errmsg -- localtime failed.\n", MyName); X perror (MyName); X fflush (stderr); X (void)flock (fileno (stderr), LOCK_UN); X return; X } X X strftime (time_stamp, sizeof (time_stamp), "%b %d %H:%M:%S", tmp); X fprintf (stderr, "%s %s[%d]: ", time_stamp, MyName, (int)getpid ()); X X va_start (args, fmt); X vfprintf (stderr, fmt, args); X va_end (args); X X if (! strchr (fmt, '\n')) X fputc ('\n', stderr); X X fflush (stderr); X X if (flock (fileno (stderr), LOCK_UN) == -1) { X fprintf (stderr, "%s: errmsg -- can't unlock log.\n", MyName); X perror (MyName); X fflush (stderr); X return; X } X } X X Xstatic struct program * Xfetch_schedule (const char *database) X { X DB *dbp; X DBC *dbcp; X DBT data; X DBT key; X char lock_file[MAXPATHLEN]; X char *buf; X char *ptr; X int fd; X int len; X int ret; X struct program *pp; X struct program *next; X struct tm tm; X struct tm *tmp; X time_t now; X X len = snprintf (lock_file, sizeof (lock_file), "%s.lck", database); X if (len <= 0 || len >= sizeof (lock_file)) { X errmsg ("fetch_schedule -- can't generate lock filename.\n"); X return NULL; X } X X if ((fd = open (lock_file, O_RDONLY)) < 0) { X char *errstr = strerror (errno); X X errmsg ("fetch_schedule -- can't open lock file.\n"); X errmsg (errstr); X return NULL; X } X X if (flock (fd, LOCK_SH) == -1) { X char *errstr = strerror (errno); X X errmsg ("fetch_schedule -- can't lock database.\n"); X errmsg (errstr); X close (fd); X return NULL; X } X X if ((ret = db_create (&dbp, NULL, 0)) != 0) { X errmsg ("db_create: %s\n", db_strerror (ret)); X close (fd); X return NULL; X } X X dbp->set_errpfx (dbp, MyName); X X if ((ret = dbp->open (dbp, NULL, database, NULL, X DB_BTREE, DB_RDONLY | DB_FCNTL_LOCKING, 0)) != 0) { X dbp->err (dbp, ret, "DB->open failed for %s", database); X dbp->close (dbp, 0); X close (fd); X return NULL; X } X X if ((ret = dbp->cursor (dbp, NULL, &dbcp, 0)) != 0) { X dbp->err (dbp, ret, "DB->cursor failed"); X dbp->close (dbp, 0); X close (fd); X return NULL; X } X X memset (&key, 0, sizeof (key)); X memset (&data, 0, sizeof (data)); X X buf = NULL; X X pp = NULL; X next = NULL; X X while ((ret = dbcp->c_get (dbcp, &key, &data, DB_NEXT)) == 0) { X if (! (buf = malloc (data.size + 1)) ) { X char *errstr = strerror (errno); X X errmsg ("fetch_schedule -- can't allocate buffer.\n"); X errmsg (errstr); X break; X } X X memcpy (buf, (char *)data.data, data.size); X buf[data.size] = '\0'; X X if (! (pp = (struct program *)calloc (1, sizeof (struct program))) ) { X char *errstr = strerror (errno); X X errmsg ("fetch_schedule -- can't allocate program.\n"); X errmsg (errstr); X break; X } X X if (! (ptr = strtok (buf, ",")) ) { X errmsg ("fetch_schedule -- can't parse channel.\n"); X break; X } X pp->channel = atoi (ptr); X X if (! (ptr = strtok (NULL, ",")) ) { X errmsg ("fetch_schedule -- can't parse quality.\n"); X break; X } X pp->quality = dvd_qt; X if (strcasecmp (ptr, "vcd") == 0) X pp->quality = vcd_qt; X else if (strcasecmp (ptr, "svcd") == 0) X pp->quality = svcd_qt; X X time (&now); X if (! (tmp = localtime (&now)) ) { X errmsg ("fetch_schedule -- localtime failed.\n"); X break; X } X tm = *tmp; X X if (! (ptr = strtok (NULL, ",")) || ! strptime (ptr, "%m/%d/%Y", &tm)) { X errmsg ("fetch_schedule -- can't parse date.\n"); X break; X } X X if (! (ptr = strtok (NULL, ",")) || ! strptime (ptr, "%H:%M", &tm)) { X errmsg ("fetch_schedule -- can't parse start.\n"); X break; X } X pp->start = mktime (&tm); X X if (! (ptr = strtok (NULL, ",")) || ! strptime (ptr, "%H:%M", &tm)) { X errmsg ("fetch_schedule -- can't parse stop.\n"); X break; X } X pp->stop = mktime (&tm); X X if (difftime (pp->stop, pp->start) < 0) { X tm.tm_mday += 1; X pp->stop = mktime (&tm); X } X X if (! (ptr = strtok (NULL, ",")) ) { X errmsg ("fetch_schedule -- can't parse repeat.\n"); X break; X } X pp->repeat = none_rpt; X if (strcasecmp (ptr, "daily") == 0) X pp->repeat = daily_rpt; X else if (strcasecmp (ptr, "weekly") == 0) X pp->repeat = weekly_rpt; X X if (pp->repeat == daily_rpt || pp->repeat == weekly_rpt) X while (difftime (pp->stop, now) <= 0) { X if (! (tmp = localtime (&pp->start)) ) { X errmsg ("fetch_schedule -- can't adjust start.\n"); X break; X } X tm = *tmp; X tm.tm_mday += (pp->repeat == daily_rpt) ? 1 : 7; X pp->start = mktime (&tm); X X if (! (tmp = localtime (&pp->stop)) ) { X errmsg ("fetch_schedule -- can't adjust stop.\n"); X break; X } X tm = *tmp; X tm.tm_mday += (pp->repeat == daily_rpt) ? 1 : 7; X pp->stop = mktime (&tm); X } X X ptr += strlen (ptr) + 1; X while (isspace (*ptr)) X ptr++; X if (strpbrk (ptr, "\\/.:")) { X errmsg ("fetch_schedule -- invalid character in name.\n"); X break; X } X if ( !(pp->name = strdup (ptr)) ) { X char *errstr = strerror (errno); X X errmsg ("fetch_schedule -- can't allocate name.\n"); X errmsg (errstr); X break; X } X X pp->next = next; X next = pp; X pp = NULL; X X free (buf); X } X X dbcp->c_close (dbcp); X X if (ret != DB_NOTFOUND) { X if (ret != 0) X dbp->err (dbp, ret, "DBcursor->get failed"); X if (buf) X free (buf); X if (pp) X free (pp); X for (pp = next; pp; pp = next) { X next = pp->next; X free (pp->name); X free (pp); X } X dbp->close (dbp, 0); X close (fd); X return NULL; X } X X dbp->close (dbp, 0); X close (fd); X X if (! next) { X if (! (next = (struct program *)calloc (1, sizeof (struct program))) ) { X char *errstr = strerror (errno); X X errmsg ("fetch_schedule -- can't allocate program.\n"); X errmsg (errstr); X return NULL; X } X if ( !(next->name = strdup ("")) ) { X char *errstr = strerror (errno); X X errmsg ("fetch_schedule -- can't allocate name.\n"); X errmsg (errstr); X free (next); X return NULL; X } X } X X return next; X } X X Xstatic int Xopen_video_source (unsigned int video_unit) X { X char video_file[MAXPATHLEN]; X int fd; X int len; X X len = snprintf (video_file, sizeof (video_file), "/dev/bktr%u", video_unit); X if (len <= 0 || len >= sizeof (video_file)) { X errmsg ("open_video_source -- can't generate video device filename.\n"); X return -1; X } X X if ((fd = open (video_file, O_RDONLY)) < 0) { X char *errstr = strerror (errno); X X errmsg ("open_video_source -- can't open %s for input.\n", video_file); X errmsg (errstr); X return -1; X } X X return fd; X } X X Xstatic int Xrecord_program (struct program *pp, const char *output_directory, X unsigned int video_unit) X { X char buffer[512000]; X char output_file[MAXPATHLEN]; X char time_stamp[256]; X int afc; X int capture_command; X int done; X int ofd; X int vfd; X int len; X int ret; X sigset_t original_signal_set; X ssize_t nbytes_read; X struct bktr_capture_area capture_area; X struct pollfd fds; X struct tm *tmp; X time_t now; X X /* X * Open the video capture card. X */ X X if ((vfd = open_video_source (video_unit)) < 0) { X errmsg ("record_program -- open_video_source failed.\n"); X return -1; X } X X /* X * Set the channel. X * X * A failure isn't considered fatal since it may simply be X * that no station is at the specified channel. X */ X X afc = 1; X X if (ioctl (vfd, TVTUNER_SETAFC, &afc) < 0) { X errmsg ("record_program -- TVTUNER_SETAFC failed.\n"); X close (vfd); X return -1; X } X X if (ioctl (vfd, TVTUNER_SETCHNL, &pp->channel) < 0) { X close (vfd); X return 0; X } X X /* X * Set the quality. X */ X X memset (&capture_area, 0, sizeof (capture_area)); X X capture_area.x_offset = 0; X capture_area.y_offset = 0; X X switch (pp->quality) { X case vcd_qt: X capture_area.x_size = 352; X capture_area.y_size = 240; X break; X X case svcd_qt: X capture_area.x_size = 480; X capture_area.y_size = 480; X break; X X default: X capture_area.x_size = 720; X capture_area.y_size = 480; X break; X } X X if (ioctl (vfd, BT848_SCAPAREA, &capture_area) < 0) { X errmsg ("record_program -- BT848_SCAPAREA failed.\n"); X close (vfd); X return -1; X } X X done = 0; X X while (! done) { X X /* X * Generate the output filename. X */ X X if (! (tmp = localtime (&pp->start)) ) { X errmsg ("record_program -- localtime failed.\n"); X close (vfd); X return -1; X } X X strftime (time_stamp, sizeof (time_stamp), "%m-%d-%Y %H%M", tmp); X X len = snprintf (output_file, sizeof (output_file), X (strlen (pp->name) ? "%s/%s %u %s.mpg" X : "%s/%s %u.mpg"), X output_directory, time_stamp, pp->channel, pp->name); X if (len <= 0 || len >= sizeof (output_file)) { X errmsg ("record_program -- can't generate output filename.\n"); X close (vfd); X return -1; X } X X /* X * Open the output file. X */ X X if ((ofd = open (output_file, O_WRONLY | O_CREAT | O_EXCL, 0644)) < 0) { X char *errstr = strerror (errno); X X if (access (output_file, F_OK) == 0) { X X /* X * We've already attempted to record the program. X */ X X close (vfd); X return 0; X } X X errmsg ("record_program -- can't open %s for output.\n", output_file); X errmsg (errstr); X close (vfd); X return -1; X } X X /* X * Record the video. X */ X X while (! done) { X if ((nbytes_read = read (vfd, buffer, sizeof (buffer))) <= 0 X || write (ofd, buffer, nbytes_read) != nbytes_read) { X char *errstr = strerror (errno); X X errmsg ("record_program -- read or write failed.\n"); X errmsg (errstr); X close (vfd); X close (ofd); X return -1; X } X X /* X * Allow signals to be processed for .1 millisecond X * so that shutdown_server can be updated. X */ X X sigprocmask (SIG_UNBLOCK, &block_signal_set, &original_signal_set); X usleep (100); X sigprocmask (SIG_SETMASK, &original_signal_set, NULL); X X time (&now); X X done = shutdown_server || difftime (pp->stop, now) <= 0; X } X X capture_command = METEOR_CAP_STOP_CONT; X X if (ioctl (vfd, METEORCAPTUR, &capture_command) < 0) { X errmsg ("record_program -- METEORCAPTUR failed.\n"); X close (vfd); X close (ofd); X return -1; X } X X fds.fd = vfd; X fds.events = POLLIN; X X while (poll (&fds, 1, 0) == 1 && (fds.revents & POLLIN)) X if ((nbytes_read = read (vfd, buffer, sizeof (buffer))) <= 0 X || write (ofd, buffer, nbytes_read) != nbytes_read) { X char *errstr = strerror (errno); X X errmsg ("record_program -- read or write failed.\n"); X errmsg (errstr); X close (vfd); X close (ofd); X return -1; X } X X close (ofd); X } X X close (vfd); X X return 1; X } X X Xstatic void Xusage () X { X X fprintf (stderr, "usage: %s [-d] [-f database] [-o outputdir]\n", MyName); X } X X Xint Xmain (int argc, char **argv) X { X const char *db; X const char *output_directory; X double diff; X int c; X int debug; X unsigned int delta; X sigset_t original_signal_set; X struct program program; X struct program *pp; X struct program *next; X struct stat statbuf; X time_t now; X X db = DATABASE; X debug = 0; X output_directory = "."; X X while ((c = getopt (argc, argv, "df:o:")) != EOF) X switch (c) { X case 'd': X debug = 1; X break; X X case 'f': X db = optarg; X break; X X case 'o': X output_directory = optarg; X break; X X default: X usage (); X exit (1); X /* NOTREACHED */ X break; X } X X if (stat (output_directory, &statbuf) < 0 X || (statbuf.st_mode & S_IFMT) != S_IFDIR) { X char *errstr = strerror (errno); X X errmsg ("stat failed for %s\n", output_directory); X errmsg ("or the path isn't a directory.\n"); X errmsg (errstr); X exit (1); X } X X if (! debug) X daemonize (); X X sigemptyset(&block_signal_set); X sigaddset(&block_signal_set, SIGHUP); X sigaddset(&block_signal_set, SIGINT); X sigaddset(&block_signal_set, SIGTERM); X X if (signal (SIGHUP, SIG_IGN) != SIG_IGN) X (void)signal (SIGHUP, catch_signal); X if (signal (SIGINT, SIG_IGN) != SIG_IGN) X (void)signal (SIGINT, catch_signal); X (void)signal (SIGTERM, catch_signal); X X sigprocmask (SIG_BLOCK, &block_signal_set, NULL); X X while (! shutdown_server) { X if (! (pp = fetch_schedule (db)) ) { X errmsg ("fetch_schedule failed.\n"); X exit (1); X } X X delta = CHECK_DATABASE_SECONDS; X memset (&program, 0, sizeof (program)); X time (&now); X X while (pp) { X next = pp->next; X X if (difftime (now, pp->start) >= 0 && difftime (now, pp->stop) < 0) { X program = *pp; X program.name = strdup (pp->name); X X if (pp->name && ! program.name) { X char *errstr = strerror (errno); X X errmsg ("strdup failed.\n"); X errmsg (errstr); X exit (1); X } X } X X diff = difftime (pp->start, now); X if (diff > 0 && diff < delta) X delta = (unsigned int) diff; X X free (pp->name); X free (pp); X pp = next; X } X X if (program.start != program.stop) { X switch (record_program (&program, output_directory, 0)) { X case 1: X continue; X /* NOTREACHED */ X break; X X case 0: X X /* X * We've already attempted to record the program. X */ X X delta = CHECK_DATABASE_SECONDS; X diff = difftime (now, program.stop); X if (diff > 0 && diff < delta) X delta = (unsigned int) diff; X break; X X default: X errmsg ("record_program failed.\n"); X exit (1); X /* NOTREACHED */ X break; X } X } X X /* X * Allow signals to be processed until the next database check is due. X */ X X sigprocmask (SIG_UNBLOCK, &block_signal_set, &original_signal_set); X while (! shutdown_server && (delta = sleep (delta)) != 0) X ; X sigprocmask (SIG_SETMASK, &original_signal_set, NULL); X } X X exit (0); X } END-of-tvrec/src/tvrecd.c echo c - tvrec/data mkdir -p tvrec/data > /dev/null 2>&1 echo c - tvrec/htdocs mkdir -p tvrec/htdocs > /dev/null 2>&1 echo x - tvrec/htdocs/scheddeli.php sed 's/^X//' >tvrec/htdocs/scheddeli.php << 'END-of-tvrec/htdocs/scheddeli.php' X END-of-tvrec/htdocs/scheddeli.php echo x - tvrec/htdocs/sched.php sed 's/^X//' >tvrec/htdocs/sched.php << 'END-of-tvrec/htdocs/sched.php' X X X X X X X X X Carmen Webserver -- TV Recording X X X X

TV X recording


X X X X X X X X X X X X X X X X X X X X'; X X echo << X X X X X X XEND; X } X X dba_close ($id); X?> X X X
Current Program(s)
ProgramChannel
1-125
QualityDate
mm/dd/yyyy
Start
HH:MM
Stop
HH:MM
RepeatNameAction
$key$pieces[0]$pieces[1]$pieces[2]$pieces[3]$pieces[4]$pieces[5]$pieces[6]Change X Delete
X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X XEND; X?> X X
X Program
ProgramChannel
1-125
QualityDate
mm/dd/yyyy
Start
HH:MM
Stop
HH:MM
RepeatNameAction
X X'; X if (isset ($error['key'])) X echo 'Program must be between 1 and 99.
'; X if (isset ($error['channel'])) X echo 'Channel must be between 1 and 125.
'; X if (isset ($error['date'])) X echo 'Date should be month/day/year.
'; X if (isset ($error['start'])) X echo 'Start time must be hour:minute.
'; X if (isset ($error['stop'])) X echo 'Stop time must be hour:minute.
'; X if (isset ($error['name'])) X echo 'Name can not contain a backslash, colon, decimal point, or slash.
'; X } X?> X
X

HOME


X X X END-of-tvrec/htdocs/sched.php echo x - tvrec/htdocs/schedaddi.php sed 's/^X//' >tvrec/htdocs/schedaddi.php << 'END-of-tvrec/htdocs/schedaddi.php' X 125) X $error['channel'] = 1; X X $now = getdate (); X X $pieces = explode ('/', $_POST['date']); X X if (count ($pieces) == 1) X if (is_numeric ($pieces[0])) X $pieces = array ($now['mon'], $pieces[0], $now['year']); X else if (! empty ($pieces[0])) X $pieces = explode ('/', strftime ('%m/%d/%Y', strtotime ($pieces[0]))); X X if (count ($pieces) == 2) X $pieces = array ($pieces[0], $pieces[1], $now['year']); X X if (count ($pieces) != 3 X || ! is_numeric ($pieces[0]) X || intval ($pieces[0]) != (double)$pieces[0] X || ! is_numeric ($pieces[1]) X || intval ($pieces[1]) != (double)$pieces[1] X || ! is_numeric ($pieces[2]) X || intval ($pieces[2]) != (double)$pieces[2]) X $error['date'] = 1; X else { X if ((int)$pieces[2] >= 0 && (int)$pieces[2] < 100) { X $century = intval ($now['year'] / 100) * 100; X $pieces[2] += $century; X } X X if ((int)$pieces[2] < 1000 X || ! checkdate ($pieces[0], $pieces[1], $pieces[2]) ) X $error['date'] = 1; X else X $_POST['date'] = sprintf ('%02d/%02d/%04d', X (int)$pieces[0], (int)$pieces[1], X (int)$pieces[2]); X } X X $pieces = explode (':', $_POST['start']); X X if (count ($pieces) != 2 X || ! is_numeric ($pieces[0]) X || intval ($pieces[0]) != (double)$pieces[0] X || (int)$pieces[0] < 0 || (int)$pieces[0] > 23 X || ! is_numeric ($pieces[1]) X || intval ($pieces[1]) != (double)$pieces[1] X || (int)$pieces[1] < 0 || (int)$pieces[1] > 59) X $error['start'] = 1; X else X $_POST['start'] = sprintf ('%02d:%02d', (int)$pieces[0], (int)$pieces[1]); X X $pieces = explode (':', $_POST['stop']); X X if (count ($pieces) != 2 X || ! is_numeric ($pieces[0]) X || intval ($pieces[0]) != (double)$pieces[0] X || (int)$pieces[0] < 0 || (int)$pieces[0] > 23 X || ! is_numeric ($pieces[1]) X || intval ($pieces[1]) != (double)$pieces[1] X || (int)$pieces[1] < 0 || (int)$pieces[1] > 59) X $error['stop'] = 1; X else X $_POST['stop'] = sprintf ('%02d:%02d', (int)$pieces[0], (int)$pieces[1]); X X if (strpos ($_POST['name'], '\\') !== FALSE X || strpos ($_POST['name'], '/') !== FALSE X || strpos ($_POST['name'], '.') !== FALSE X || strpos ($_POST['name'], ':') !== FALSE) X $error['name'] = 1; X else X $_POST['name'] = trim ($_POST['name']); X X if (is_array ($error)) { X include (TVR_BASE . 'htdocs/sched.php'); X return; X } X X $record = $_POST['channel'] . ',' . $_POST['quality'] . ',' X . $_POST['date'] . ',' . $_POST['start'] . ',' X . $_POST['stop'] . ',' . $_POST['repeat'] . ',' X . $_POST['name']; X X $id = dba_open (TVR_BASE . $conf['tvr']['db_name'], 'cl', $conf['tvr']['db_type']); X X $key = ''; X X if (isset ($_POST['key']) && is_numeric ($_POST['key'])) X $key = $_POST['key']; X else { X $prevkey = 0; X X for ($key = dba_firstkey ($id); $key != false; $key = dba_nextkey ($id)) { X if (! is_numeric ($key) ) X continue; X if ((int)$key > (int)($prevkey + 1)) X break; X $prevkey = $key; X } X X $key = sprintf ("%02d", $prevkey + 1); X } X X if (intval ($key) != (double)$key X || (int)$key < 1 || (int)$key > 99) { X $error['key'] = 1; X dba_close ($id); X include (TVR_BASE . 'htdocs/sched.php'); X return; X } X X dba_replace ($key, $record, $id); X X dba_sync ($id); X X dba_close ($id); X X header ('Location: ' . $tvr_webroot . '/sched.php'); X?> END-of-tvrec/htdocs/schedaddi.php exit ------------------------------------------------------------------------- | Feith Systems | Voice: 1-215-646-8000 | Email: john@feith.com | | John Wehle | Fax: 1-215-540-5495 | | -------------------------------------------------------------------------