summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorroot <root@lwg5001.(none)>2008-12-18 08:46:41 +0100
committerroot <root@lwg5001.(none)>2008-12-18 08:46:41 +0100
commit0a38f9f8cde03a188c79f66dc4b005d83a6f0cfd (patch)
treeac9bcbdab8b2a3c23423d7dd14278cd6d77606de
parentf381118bd3f91740edc5bf464ab1300938f3ec5d (diff)
downloadvdr-plugin-infosatepg-0a38f9f8cde03a188c79f66dc4b005d83a6f0cfd.tar.gz
vdr-plugin-infosatepg-0a38f9f8cde03a188c79f66dc4b005d83a6f0cfd.tar.bz2
Initial commit
-rw-r--r--COPYING340
-rw-r--r--DELETE.ME0
-rw-r--r--HISTORY31
-rw-r--r--Makefile112
-rw-r--r--README18
-rw-r--r--filter.cpp187
-rw-r--r--filter.h44
-rw-r--r--global.cpp334
-rw-r--r--global.h184
-rw-r--r--infosatepg.cpp258
-rw-r--r--infosatepg.h46
-rw-r--r--po/de_DE.po61
-rw-r--r--process.cpp598
-rw-r--r--process.h83
-rw-r--r--readline.cpp70
-rw-r--r--readline.h23
-rw-r--r--setup.cpp149
-rw-r--r--setup.h49
-rw-r--r--status.cpp63
-rw-r--r--status.h29
20 files changed, 2679 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 of the License, 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; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/DELETE.ME b/DELETE.ME
deleted file mode 100644
index e69de29..0000000
--- a/DELETE.ME
+++ /dev/null
diff --git a/HISTORY b/HISTORY
new file mode 100644
index 0000000..2d2029d
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,31 @@
+VDR Plugin 'infosatepg' Revision History
+----------------------------------------
+
+2008-12-17: Version 0.0.5
+
+- Changed channel setup
+- Changed algorithm to find a free device
+- Added SVDRP status
+
+2008-11-11: Version 0.0.4
+
+- Added fix from LiamHD
+
+2008-06-18: Version 0.0.3
+
+- Changed function to find event
+- Added setup value usePrimary
+- Lock filter after complete reception
+- Delete old data files
+
+2008-06-15: Version 0.0.2
+
+- Changed function to find event
+- Setup value WaitTime wasn't used
+- Added setup value EventTimeDiff
+- Fixed some bugs in process.cpp
+- Minor changes to Makefile
+
+2008-05-01: Version 0.0.1
+
+- Initial revision.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d654623
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,112 @@
+#
+# Makefile for a Video Disk Recorder plugin
+#
+# $Id$
+
+# The official name of this plugin.
+# This name will be used in the '-P...' option of VDR to load the plugin.
+# By default the main source file also carries this name.
+# IMPORTANT: the presence of this macro is important for the Make.config
+# file. So it must be defined, even if it is not used here!
+#
+PLUGIN = infosatepg
+
+### The version number of this plugin (taken from the main source file):
+
+VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).h | awk '{ print $$6 }' | sed -e 's/[";]//g')
+
+### The C++ compiler and options:
+
+CXX ?= g++
+CXXFLAGS ?= -fPIC -g0 -O2 -Wall -Woverloaded-virtual -Wno-parentheses
+
+### The directory environment:
+
+VDRDIR = ../../..
+LIBDIR = ../../lib
+TMPDIR = /tmp
+
+### Allow user defined options to overwrite defaults:
+
+-include $(VDRDIR)/Make.config
+
+### The version number of VDR's plugin API (taken from VDR's "config.h"):
+
+APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h)
+
+### The name of the distribution archive:
+
+ARCHIVE = $(PLUGIN)-$(VERSION)
+PACKAGE = vdr-$(ARCHIVE)
+
+### Includes and Defines (add further entries here):
+
+INCLUDES += -I$(VDRDIR)/include
+
+DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o global.o setup.o filter.o status.o readline.o process.o
+
+### The main target:
+
+all: libvdr-$(PLUGIN).so i18n
+
+### Implicit rules:
+
+%.o: %.cpp
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+### Dependencies:
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.cpp) > $@
+
+-include $(DEPFILE)
+
+### Internationalization (I18N):
+
+PODIR = po
+LOCALEDIR = $(VDRDIR)/locale
+I18Npo = $(wildcard $(PODIR)/*.po)
+I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
+I18Npot = $(PODIR)/$(PLUGIN).pot
+
+%.mo: %.po
+ msgfmt -c -o $@ $<
+
+$(I18Npot): $(wildcard *.cpp *.h)
+ xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='<see README>' -o $@ $^
+
+%.po: $(I18Npot)
+ msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
+ @touch $@
+
+$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
+ @mkdir -p $(dir $@)
+ cp $< $@
+
+.PHONY: i18n
+i18n: $(I18Nmsgs) $(I18Npot)
+
+
+### Targets:
+
+libvdr-$(PLUGIN).so: $(OBJS)
+ $(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@
+ @cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
+
+dist: clean
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @mkdir $(TMPDIR)/$(ARCHIVE)
+ @cp -a *.cpp *.h $(TMPDIR)/$(ARCHIVE)
+ @cp -a po COPYING HISTORY README Makefile $(TMPDIR)/$(ARCHIVE)
+ @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE)
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @echo Distribution package created as $(PACKAGE).tgz
+
+clean:
+ @-rm -f $(OBJS) $(DEPFILE) *.so* *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot
diff --git a/README b/README
new file mode 100644
index 0000000..90b24e6
--- /dev/null
+++ b/README
@@ -0,0 +1,18 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by: Jochen Dolze <vdr@dolze.de>
+
+Project's homepage: http://projects.vdr-developer.org/projects/show/plg-infosatepg
+
+Latest version available at: http://projects.vdr-developer.org/projects/show/plg-infosatepg
+
+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 of the License, or
+(at your option) any later version.
+See the file COPYING for more information.
+
+Description:
+
+Reads the contents of infosat and writes the data into the
+EPG.
diff --git a/filter.cpp b/filter.cpp
new file mode 100644
index 0000000..7a3bc89
--- /dev/null
+++ b/filter.cpp
@@ -0,0 +1,187 @@
+/*
+ * filter.cpp: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#include <netinet/if_ether.h>
+#include <unistd.h>
+
+#include "filter.h"
+
+#undef WRITE_RAW
+
+cFilterInfosatepg::cFilterInfosatepg(cGlobalInfosatepg *Global)
+{
+ global = Global;
+ Set(global->Pid,0,0);
+}
+
+u_long cFilterInfosatepg::do_sum(u_long sum, u_char *buf, int nBytes)
+{
+ int nleft=nBytes;
+ u_short *w = (u_short*)buf;
+
+ while (nleft > 1)
+ {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ if (nleft == 1)
+ {
+ u_short answer = 0;
+ *(u_char*)(&answer) = *(u_char*)w;
+ sum += answer;
+ }
+ return sum;
+}
+
+u_short cFilterInfosatepg::foldsum(u_long sum)
+{
+ while (sum>>16)
+ sum = (sum >> 16) + (sum & 0xFFFF);
+
+ return ((u_short) ~sum);
+}
+
+u_short cFilterInfosatepg::IPChecksum(iphdr *ipHeader)
+{
+ return foldsum(do_sum(0, (u_char*) ipHeader, sizeof(iphdr)));
+
+} /* IpChecksum() */
+
+
+u_short cFilterInfosatepg::UDPChecksum(iphdr *ipHeader, udphdr *udpHeader)
+{
+ u_long sum = 0;
+
+ // Ip-Pseudo-Header
+ sum = do_sum(sum, (u_char*)(&ipHeader->saddr), sizeof(ipHeader->saddr));
+ sum = do_sum(sum, (u_char*)(&ipHeader->daddr), sizeof(ipHeader->daddr));
+ sum += udpHeader->len;
+ sum += ipHeader->protocol<<8;
+
+ sum = do_sum(sum, (u_char*)udpHeader, ntohs(udpHeader->len));
+
+ return foldsum(sum);
+}
+
+
+void cFilterInfosatepg::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
+{
+#define SECT_IP_HDR_START 12
+#define SECT_UDP_HDR_START 32
+#define SECT_IS_HDR_START 40
+#define SECT_IS_DATA_START 52
+
+ if (Data[0]!=0x3E) return;
+
+ struct ethhdr eth_hdr;
+ memset(&eth_hdr,0,sizeof(struct ethhdr));
+
+ eth_hdr.h_dest[0]=Data[11];
+ eth_hdr.h_dest[1]=Data[10];
+ eth_hdr.h_dest[2]=Data[9];
+ eth_hdr.h_dest[3]=Data[8];
+ eth_hdr.h_dest[4]=Data[4];
+ eth_hdr.h_dest[5]=Data[3];
+
+ if (!global->CheckMAC(&eth_hdr)) return;
+
+ int mac = eth_hdr.h_dest[5];
+
+ struct iphdr *ip_hdr = (iphdr *) &Data[SECT_IP_HDR_START];
+ struct udphdr *udp_hdr = (udphdr *) &Data[SECT_UDP_HDR_START];
+
+ // Only IPv4
+ if (ip_hdr->version!=4) return;
+
+ // Check IP checksum
+ if (IPChecksum(ip_hdr)!=0)
+ {
+ dsyslog("infosatepg: ip checksum error");
+ return;
+ }
+
+ // Only UDP
+ if (ip_hdr->protocol!=17) return;
+
+ // Check UDP checksum
+ if (UDPChecksum(ip_hdr,udp_hdr)!=0)
+ {
+ dsyslog("infosatepg: udp checksum error");
+ return;
+ }
+
+ struct infosathdr *ishdr = (struct infosathdr*) &Data[SECT_IS_HDR_START];
+
+ if (ntohs(ishdr->technisatId)!=0x0001) return;
+
+ const u_char *infosatdata = &Data[SECT_IS_DATA_START];
+ int len = Length - SECT_IS_DATA_START-4;
+
+ char file[1024];
+ snprintf(file,sizeof(file),"%s/infosatepg%02i%02i_%03i.dat",global->Directory(),ishdr->day,ishdr->month,
+ ntohs(ishdr->pktcnt));
+
+ if (global->Infosatdata[mac].NeverSeen(ishdr->day,ishdr->month,ntohs(ishdr->pktcnt)))
+ {
+ // never seen such a packet -> init structure
+ global->Infosatdata[mac].Init(file,ishdr->day,ishdr->month,ntohs(ishdr->pktcnt));
+ }
+
+ // Check if we already have this packet
+ if (global->Infosatdata[mac].GetBit(ntohs(ishdr->pktnr))) return;
+
+ // set bit in Infosatdata bitfield
+ global->Infosatdata[mac].SetBit(ntohs(ishdr->pktnr),true);
+
+#ifdef VDRDEBUG
+ dsyslog("infosatepg: mac=%02x-%02x-%02x-%02x-%02x-%02x",eth_hdr.h_dest[0],eth_hdr.h_dest[1],
+ eth_hdr.h_dest[2],eth_hdr.h_dest[3],eth_hdr.h_dest[4],eth_hdr.h_dest[5] );
+
+ dsyslog("infosatepg: tid=%04i tbl=%04i stbl=%04i day=%02i month=%02i pktnr=%03i pktcnt=%03i len=%i",
+ ntohs(ishdr->technisatId),ishdr->tableId,ishdr->tablesubId,ishdr->day,
+ ishdr->month, ntohs(ishdr->pktnr), ntohs(ishdr->pktcnt), len);
+
+ dsyslog("infosatepg: save to %s", file);
+#endif
+
+ int f=open(file,O_RDWR|O_CREAT,0664);
+ if (f==-1)
+ {
+ if (errno!=ENOSPC)
+ {
+ esyslog("infosatepg: unable to create file '%s'", file);
+ }
+ return;
+ }
+ off_t offset = (off_t) (ntohs(ishdr->pktnr)*1400);
+ if (lseek(f,offset,SEEK_SET)!=(off_t) -1)
+ {
+#ifdef VDRDEBUG
+ dsyslog("infosatepg: writing to %li",offset);
+#endif
+ write(f,infosatdata,len);
+ }
+ close(f);
+
+#ifdef WRITE_RAW
+ sprintf(file,"%s/%03i.dat",dir,ntohs(ishdr->pktnr));
+ f=open(file,O_RDWR|O_CREAT,0664);
+ if (f==-1) return;
+ write(f,Data,Length);
+ close(f);
+#endif
+
+ // check if we have all packets
+ if (global->Infosatdata[mac].ReceivedAll())
+ {
+ // we have all packets
+ isyslog("infosatepg: day=%02i month=%02i fully received", ishdr->day,ishdr->month);
+ }
+
+}
diff --git a/filter.h b/filter.h
new file mode 100644
index 0000000..a21b1ff
--- /dev/null
+++ b/filter.h
@@ -0,0 +1,44 @@
+/*
+ * filter.cpp: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#ifndef __filter_h_
+#define __filter_h_
+
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <vdr/filter.h>
+
+#include "global.h"
+
+struct infosathdr {
+ u_short technisatId;
+ u_char tableId;
+ u_char tablesubId;
+ u_char day;
+ u_char month;
+ u_char res6;
+ u_char res7;
+ u_short pktnr;
+ u_short pktcnt;
+};
+
+// --- cFilterInfosatepg
+class cFilterInfosatepg : public cFilter {
+private:
+ cGlobalInfosatepg *global;
+ u_long do_sum(u_long sum, u_char *buf, int nBytes);
+ u_short foldsum(u_long sum);
+ u_short IPChecksum(iphdr *ipHeader);
+ u_short UDPChecksum(iphdr *ipHeader, udphdr *udpHeader);
+protected:
+ virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
+public:
+ cFilterInfosatepg(cGlobalInfosatepg *Global);
+ };
+
+#endif
diff --git a/global.cpp b/global.cpp
new file mode 100644
index 0000000..0cf65ba
--- /dev/null
+++ b/global.cpp
@@ -0,0 +1,334 @@
+#include <vdr/channels.h>
+#include "global.h"
+
+// --- cGlobalInfosatdata
+cGlobalInfosatdata::cGlobalInfosatdata()
+{
+ file[0]=0;
+ Init(NULL,0,0,0);
+}
+
+bool cGlobalInfosatdata::NeverSeen(int Day, int Month, int Packetcount)
+{
+ if ((day!=Day) || (month!=Month) || (pktcnt!=Packetcount))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void cGlobalInfosatdata::Init(char *File, int Day, int Month, int Packetcount)
+{
+ if (access(file,R_OK)==0)
+ {
+ dsyslog("infosatepg: deleting old %s",file);
+ unlink(file);
+ }
+ ready=false;
+ processed=false;
+ day=Day;
+ month=Month;
+ pktcnt=Packetcount;
+ if (File) snprintf(file,sizeof(file),"%s",File);
+ else file[0]=0;
+ memset(bitfield,0,sizeof(bitfield));
+}
+
+int cGlobalInfosatdata::Save(int fd)
+{
+ if (fd==-1) return -1;
+ ssize_t ret=write(fd,&ready,sizeof(ready));
+ if (ret!=sizeof(ready)) return -1;
+ ret=write(fd,&processed,sizeof(processed));
+ if (ret!=sizeof(processed)) return -1;
+ ret=write(fd,&day,sizeof(day));
+ if (ret!=sizeof(day)) return -1;
+ ret=write(fd,&month,sizeof(month));
+ if (ret!=sizeof(month)) return -1;
+ ret=write(fd,&pktcnt,sizeof(pktcnt));
+ if (ret!=sizeof(pktcnt)) return -1;
+ ret=write(fd,&bitfield,sizeof(bitfield));
+ if (ret!=sizeof(bitfield)) return -1;
+ ret=write(fd,&file,sizeof(file));
+ if (ret!=sizeof(file)) return -1;
+ return ret;
+}
+
+int cGlobalInfosatdata::Load(int fd)
+{
+ if (fd==-1) return -1;
+ ssize_t ret=read(fd,&ready,sizeof(ready));
+ if (ret!=sizeof(ready)) return -1;
+ ret=read(fd,&processed,sizeof(processed));
+ if (ret!=sizeof(processed)) return -1;
+ ret=read(fd,&day,sizeof(day));
+ if (ret!=sizeof(day)) return -1;
+ ret=read(fd,&month,sizeof(month));
+ if (ret!=sizeof(month)) return -1;
+ ret=read(fd,&pktcnt,sizeof(pktcnt));
+ if (ret!=sizeof(pktcnt)) return -1;
+ ret=read(fd,&bitfield,sizeof(bitfield));
+ if (ret!=sizeof(bitfield)) return -1;
+ ret=read(fd,&file,sizeof(file));
+ if (ret!=sizeof(file)) return -1;
+ dsyslog("infosatepg: loaded file=*%s*",file);
+ return ret;
+}
+
+#ifdef INFOSATEPG_DEBUG
+void cGlobalInfosatdata::Debug(const char *Directory)
+{
+ char file[1024];
+ snprintf(file,sizeof(file),"%s/infosatepg9999_999.dat",Directory);
+ Init(file,99,99,999);
+ ready=true;
+}
+#endif
+
+int cGlobalInfosatdata::ReceivedPercent()
+{
+ if (pktcnt==0) return 0;
+ int donecnt=0;
+ for (int i=0; i<pktcnt; i++)
+ {
+ if (GetBit(i)==true) donecnt++;
+ }
+ return ((donecnt*100)/pktcnt);
+}
+
+bool cGlobalInfosatdata::ReceivedAll()
+{
+ if (pktcnt==0) return false;
+ for (int i=0; i<pktcnt; i++)
+ {
+ if (GetBit(i)==false) return false;
+ }
+ ready=true;
+ return true;
+}
+
+// --- cGlobalInfosatepg -----------------------------------------------------
+cGlobalInfosatepg::cGlobalInfosatepg()
+{
+ // set default values
+ Pid=1809;
+ EventTimeDiff=480; // default 8 minutes
+ Channel=1;
+ MAC[0]=0x01;
+ MAC[1]=0x00;
+ MAC[2]=0x5e;
+ MAC[3]=0x02;
+ MAC[4]=0x02;
+ WaitTime=10; // default 10 seconds
+ Switched=false;
+ directory=NULL;
+ SetDirectory("/tmp");
+ infosatchannels=NULL;
+ numinfosatchannels=0;
+ this_day=-1;
+ this_month=-1;
+}
+
+cGlobalInfosatepg::~cGlobalInfosatepg()
+{
+ free((void *) directory);
+ free(infosatchannels);
+}
+
+bool cGlobalInfosatepg::SetDirectory(const char *Directory)
+{
+ if (access(Directory,W_OK | R_OK | X_OK)==-1)
+ {
+ // cannot access, maybe create?
+ if (mkdir(Directory,0775)==-1)
+ {
+ // even if the Directory exists, we cannot access
+ return false;
+ }
+ if (access(Directory,W_OK | R_OK| X_OK)==-1) return false;
+ }
+ free((void *) directory);
+ directory = Directory ? strdup(Directory) : NULL;
+ return true;
+}
+
+bool cGlobalInfosatepg::CheckMAC(struct ethhdr *eth_hdr)
+{
+ if (!eth_hdr) return false;
+ if (eth_hdr->h_dest[0]!=MAC[0]) return false;
+ if (eth_hdr->h_dest[1]!=MAC[1]) return false;
+ if (eth_hdr->h_dest[2]!=MAC[2]) return false;
+ if (eth_hdr->h_dest[3]!=MAC[3]) return false;
+ if (eth_hdr->h_dest[4]!=MAC[4]) return false;
+
+ if (eth_hdr->h_dest[5]<EPG_FIRST_DAY_MAC) return false;
+ if (eth_hdr->h_dest[5]>EPG_LAST_DAY_MAC) return false;
+
+ return true;
+}
+
+void cGlobalInfosatepg::AddChannel(tChannelID ChannelID,int Usage)
+{
+ infosatchannels=(struct infosatchannels *) realloc(infosatchannels,
+ (numinfosatchannels+1)*sizeof(struct infosatchannels));
+ if (!infosatchannels) return;
+ infosatchannels[numinfosatchannels].ChannelID=ChannelID;
+ infosatchannels[numinfosatchannels].Usage=Usage;
+ numinfosatchannels++;
+}
+
+tChannelID cGlobalInfosatepg::GetChannelID(int Index)
+{
+ if (numinfosatchannels==0) return tChannelID::InvalidID;
+ if ((Index<0) || (Index>numinfosatchannels-1))
+ return tChannelID::InvalidID;
+ return infosatchannels[Index].ChannelID;
+}
+
+bool cGlobalInfosatepg::ChannelExists(tChannelID ChannelID,int *Index)
+{
+ if (numinfosatchannels==0) return false;
+ for (int i=0; i<numinfosatchannels; i++)
+ {
+ if (infosatchannels[i].ChannelID==tChannelID::InvalidID) continue;
+ if (infosatchannels[i].ChannelID==ChannelID)
+ {
+ if (Index) *Index=i;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cGlobalInfosatepg::SetChannelUse(int Index,int Usage)
+{
+ if (numinfosatchannels==0) return false;
+ if ((Index<0) || (Index>numinfosatchannels-1)) return false;
+ bool ret=false;
+ if (infosatchannels[Index].Usage!=Usage) ret=true;
+ infosatchannels[Index].Usage=Usage;
+ return ret;
+}
+
+int cGlobalInfosatepg::GetChannelUse(int Index)
+{
+ if (numinfosatchannels==0) return USE_NOTHING;
+ if ((Index<0) || (Index>numinfosatchannels-1)) return USE_NOTHING;
+ return infosatchannels[Index].Usage;
+}
+
+int cGlobalInfosatepg::Save()
+{
+ char file[1024];
+ snprintf(file,sizeof(file),"%s/infosatepg.dat",directory);
+
+ int f=open(file,O_RDWR|O_CREAT|O_TRUNC,0664);
+ if (f==-1)
+ {
+ if (errno!=ENOSPC)
+ {
+ esyslog("infosatepg: unable to create file '%s'", file);
+ }
+ return -1;
+ }
+
+ int ret;
+ for (int mac=EPG_FIRST_DAY_MAC; mac<=EPG_LAST_DAY_MAC; mac++)
+ {
+ ret=Infosatdata[mac].Save(f);
+ if (ret==-1) break;
+ }
+
+ if (ret!=-1)
+ {
+ ret=write(f,&this_day,sizeof(this_day));
+ if (ret!=sizeof(this_day)) ret=-1;
+ }
+ if (ret!=-1)
+ {
+ ret=write(f,&this_month,sizeof(this_month));
+ if (ret!=sizeof(this_month)) ret=-1;
+ }
+
+ close(f);
+ if (ret==-1) unlink(file);
+ return ret;
+}
+
+int cGlobalInfosatepg::Load()
+{
+ char file[1024];
+ snprintf(file,sizeof(file),"%s/infosatepg.dat",directory);
+
+ int f=open(file,O_RDONLY);
+ if (f==-1) return 0; // it's ok if the file doesn't exist
+
+ int ret;
+ for (int mac=EPG_FIRST_DAY_MAC; mac<=EPG_LAST_DAY_MAC; mac++)
+ {
+ ret=Infosatdata[mac].Load(f);
+ if (ret==-1) break;
+ }
+ if (ret!=-1)
+ {
+ ret=read(f,&this_day,sizeof(this_day));
+ if (ret!=sizeof(this_day)) ret=-1;
+ }
+ if (ret!=-1)
+ {
+ ret=read(f,&this_month,sizeof(this_month));
+ if (ret!=sizeof(this_month)) ret=-1;
+ }
+
+ close(f);
+ if (ret==-1)
+ {
+ unlink(file); // but it's not ok if the read failed!
+ for (int mac=EPG_FIRST_DAY_MAC; mac<=EPG_LAST_DAY_MAC; mac++)
+ {
+ Infosatdata[mac].Init(NULL,0,0,0);
+ }
+
+ }
+ return ret;
+}
+
+void cGlobalInfosatepg::ResetProcessedFlags(void)
+{
+ dsyslog("infosatepg: reprocess files (later)");
+ for (int mac=EPG_FIRST_DAY_MAC; mac<=EPG_LAST_DAY_MAC; mac++)
+ {
+ Infosatdata[mac].ResetProcessed();
+ }
+}
+
+void cGlobalInfosatepg::Lock(time_t Now)
+{
+ struct tm tm;
+ if (!localtime_r(&Now,&tm))
+ {
+ this_day=-1;
+ this_month=-1;
+ }
+ else
+ {
+ if ((tm.tm_mday!=this_day) || ((tm.tm_mon+1)!=this_month))
+ isyslog("infosatepg: all data processed");
+ this_day=tm.tm_mday;
+ this_month=tm.tm_mon+1;
+ }
+}
+
+bool cGlobalInfosatepg::isLocked(int *Day, int *Month)
+{
+ if (Day) *Day=this_day;
+ if (Month) *Month=this_month;
+ time_t Now=time(NULL);
+ struct tm tm;
+ if (!localtime_r(&Now,&tm)) return false;
+ if ((tm.tm_mday==this_day) && ((tm.tm_mon+1)==this_month)) return true;
+ return false;
+}
diff --git a/global.h b/global.h
new file mode 100644
index 0000000..0484380
--- /dev/null
+++ b/global.h
@@ -0,0 +1,184 @@
+/*
+ * global.h: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#ifndef __global_h_
+#define __global_h_
+
+#include <netinet/if_ether.h>
+#include <sys/types.h>
+
+#include <vdr/channels.h>
+
+#define MIN_WAITTIME 10
+#define MAX_WAITTIME 120
+#define MIN_EVENTTIMEDIFF 5
+#define MAX_EVENTTIMEDIFF 10
+
+class cGlobalInfosatdata
+{
+#define _GetByte( ptr, bitnum ) ( (((char*)ptr)+bitnum/8) )
+#define _GetBit( ptr, bitnum ) ( (*_GetByte(ptr, bitnum) >> (bitnum%8)) & 1 )
+#define _SetBit( ptr, bitnum, val ) ( val ? \
+ (*_GetByte(ptr, bitnum) |= (1<<(bitnum%8))) : \
+ (*_GetByte(ptr, bitnum) &= ~(1<<(bitnum%8))) )
+private:
+ bool ready;
+ bool processed;
+ u_char day;
+ u_char month;
+ u_short pktcnt;
+ u_char bitfield[8192];
+ char file[1024];
+public:
+ cGlobalInfosatdata();
+ bool isReady2Process()
+ {
+ return (ready && !processed);
+ }
+ bool wasProcessed()
+ {
+ return (ready && processed);
+ }
+ int Day()
+ {
+ return day;
+ }
+ int Month()
+ {
+ return month;
+ }
+ int Packetcount()
+ {
+ return pktcnt;
+ }
+ void SetProcessed()
+ {
+ processed=true;
+ }
+ void ResetProcessed()
+ {
+ processed=false;
+ }
+ bool GetBit(int Bitnumber)
+ {
+ return _GetBit(bitfield,Bitnumber);
+ }
+ void SetBit(int Bitnumber,bool Value)
+ {
+ _SetBit(bitfield,Bitnumber,Value);
+ }
+ const char *GetFile() const
+ {
+ return (char *) &file;
+ }
+
+ bool NeverSeen(int Day, int Month, int Packetcount);
+ void Init(char *File, int Day, int Month, int Packetcount);
+ bool ReceivedAll();
+ int ReceivedPercent();
+ int Load(int fd);
+ int Save(int fd);
+#ifdef INFOSATEPG_DEBUG
+ void Debug(const char *Directory);
+#endif
+};
+
+class cGlobalInfosatepg
+{
+#define USE_NOTHING 0
+
+
+#define USE_SHORTTEXT 1
+#define USE_SHORTLONGTEXT 2
+#define USE_SHORTTEXTEPG 3
+#define USE_INTELLIGENT 4
+#define USE_ALL 5
+
+ /*
+ #define USE_NOTHING 0
+ #define USE_SHORTTEXT 1
+ #define USE_LONGTEXT 2
+ #define USE_EXTEPG 4
+ #define
+ */
+
+ struct infosatchannels
+ {
+ tChannelID ChannelID;
+ int Usage;
+ };
+
+#define EPG_FIRST_DAY_MAC 1
+#define EPG_LAST_DAY_MAC 7
+#define EPG_DAYS 7
+
+private:
+ const char *directory;
+ u_char MAC[5];
+ time_t timer;
+ bool Switched;
+ int this_day;
+ int this_month;
+public:
+ cGlobalInfosatepg();
+ ~cGlobalInfosatepg();
+ int Channel;
+ int Pid;
+ int EventTimeDiff;
+ int WaitTime;
+
+ const char *Directory()
+ {
+ return directory;
+ }
+ bool SetDirectory(const char *Directory);
+ bool CheckMAC(struct ethhdr *eth_hdr);
+ void SetTimer()
+ {
+ timer=time(NULL);
+ }
+ bool isWaitOk()
+ {
+ return (time(NULL)>(timer+(time_t) WaitTime));
+ }
+ void SetSwitched(bool Value)
+ {
+ Switched=Value;
+ }
+ bool isSwitched()
+ {
+ return Switched;
+ }
+
+public:
+ cGlobalInfosatdata Infosatdata[EPG_DAYS+1];
+ int Load();
+ int Save();
+ void Lock(time_t Now);
+ bool isLocked(int *Day, int *Month);
+ bool isLocked()
+ {
+ return isLocked(NULL,NULL);
+ }
+
+private:
+ int numinfosatchannels;
+ struct infosatchannels *infosatchannels;
+public:
+ void AddChannel(tChannelID ChannelID,int Usage);
+ tChannelID GetChannelID(int Index);
+ bool SetChannelUse(int Index,int Usage);
+ void ResetProcessedFlags(void);
+ int GetChannelUse(int Index);
+ bool ChannelExists(tChannelID ChannelID,int *Index);
+ int InfosatChannels()
+ {
+ return numinfosatchannels;
+ }
+};
+#endif
diff --git a/infosatepg.cpp b/infosatepg.cpp
new file mode 100644
index 0000000..50f04a3
--- /dev/null
+++ b/infosatepg.cpp
@@ -0,0 +1,258 @@
+/*
+ * infosatepg.cpp: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#include <vdr/plugin.h>
+#include <vdr/device.h>
+#include <vdr/channels.h>
+#include <vdr/transfer.h>
+#include <vdr/shutdown.h>
+#include <vdr/eitscan.h>
+#include <getopt.h>
+
+#include "infosatepg.h"
+#include "setup.h"
+#include "process.h"
+
+// --- cPluginInfosatepg
+cPluginInfosatepg::cPluginInfosatepg(void)
+{
+ // Initialize any member variables here.
+ // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
+ // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
+ statusMonitor=NULL;
+ global=new cGlobalInfosatepg;
+}
+
+cPluginInfosatepg::~cPluginInfosatepg()
+{
+ // Clean up after yourself!
+ if (statusMonitor) delete statusMonitor;
+ delete global;
+}
+
+const char *cPluginInfosatepg::CommandLineHelp(void)
+{
+ // Return a string that describes all known command line options.
+ return " -d DIR, --dir=DIR use DIR as infosat data directory\n"
+ " (default: /tmp)\n";
+}
+
+bool cPluginInfosatepg::ProcessArgs(int argc, char *argv[])
+{
+ // Implement command line argument processing here if applicable.
+ static struct option long_options[] =
+ {
+ { "dir", required_argument, NULL, 'd'
+ },
+ { NULL }
+ };
+
+ int c;
+ while ((c = getopt_long(argc, argv, "d:", long_options, NULL)) != -1)
+ {
+ switch (c)
+ {
+ case 'd':
+ if (global->SetDirectory(optarg))
+ {
+ isyslog("infosatepg: using directory '%s' for data",optarg);
+ }
+ else
+ {
+ fprintf(stderr,"infosatepg: can't access data directory: %s\n",
+ optarg);
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cPluginInfosatepg::Initialize(void)
+{
+ // Initialize any background activities the plugin shall perform.
+ return true;
+}
+
+bool cPluginInfosatepg::Start(void)
+{
+ // Start any background activities the plugin shall perform
+ if (global->Load()==-1)
+ {
+ isyslog("infosatepg: failed to load plugin status");
+ }
+ statusMonitor = new cStatusInfosatepg(global);
+
+#ifdef INFOSATEPG_DEBUG
+ global->Infosatdata[2].Debug(global->Directory());
+ cProcessInfosatepg process(2,global);
+#endif
+ return true;
+}
+
+void cPluginInfosatepg::Stop(void)
+{
+ // Stop any background activities the plugin is performing.
+ if (global->Save()==-1)
+ {
+ isyslog("infosatepg: failed to save plugin status");
+ }
+}
+
+void cPluginInfosatepg::Housekeeping(void)
+{
+ // Perform any cleanup or other regular tasks.
+ int numProcessed=0;
+ for (int mac=EPG_FIRST_DAY_MAC; mac<=EPG_LAST_DAY_MAC; mac++)
+ {
+ if (global->Infosatdata[mac].isReady2Process())
+ {
+ isyslog("infosatepg: janitor found data to be processed: day=%i month=%i",
+ global->Infosatdata[mac].Day(),global->Infosatdata[mac].Month());
+ cProcessInfosatepg process(mac,global);
+ }
+ if (global->Infosatdata[mac].wasProcessed())
+ {
+ numProcessed++;
+ }
+ }
+ if (numProcessed==EPG_DAYS)
+ {
+ global->Lock(time(NULL));
+ }
+}
+
+void cPluginInfosatepg::MainThreadHook(void)
+{
+ // Perform actions in the context of the main program thread.
+ if ((!global->isWaitOk()) || (global->isSwitched()) || (global->isLocked())) return;
+
+ cChannel *chan=Channels.GetByNumber(global->Channel);
+ if (!chan) return;
+
+ for (int i=0; i<cDevice::NumDevices(); i++)
+ {
+ cDevice *dev=cDevice::GetDevice(i);
+ if (dev)
+ {
+ bool live=false;
+ if (dev->IsTunedToTransponder(chan)) return; // device is already tuned to transponder -> ok
+ if (!dev->ProvidesTransponder(chan)) continue; // device cannot provide transponder -> skip
+ if (EITScanner.UsesDevice(dev)) continue; // EITScanner is updating EPG -> skip
+ if (dev->Receiving()) continue; // device is recording -> skip
+
+ if (dev->IsPrimaryDevice())
+ {
+ // just use primary ff-card if inactive
+ if (!ShutdownHandler.IsUserInactive()) continue; // not idle -> skip
+ }
+
+ if (cDevice::ActualDevice()->CardIndex()==i)
+ {
+ // LIVE device without recording, just use if inactive
+ if (!ShutdownHandler.IsUserInactive()) continue; // not idle -> skip
+ live=true;
+ }
+
+ // ok -> use this device
+ dsyslog("infosatepg: found free device %i",dev->DeviceNumber()+1);
+ dev->SwitchChannel(chan,live);
+ global->SetTimer();
+ return;
+ }
+ }
+}
+
+cString cPluginInfosatepg::Active(void)
+{
+ // Return a message string if shutdown should be postponed
+ return NULL;
+}
+
+time_t cPluginInfosatepg::WakeupTime(void)
+{
+ // Return custom wakeup time for shutdown script
+ return 0;
+}
+
+cOsdObject *cPluginInfosatepg::MainMenuAction(void)
+{
+ // Perform the action when selected from the main VDR menu.
+ return NULL;
+}
+
+cMenuSetupPage *cPluginInfosatepg::SetupMenu(void)
+{
+ // Returns the setup menu.
+ return new cMenuSetupInfosatepg(global);
+}
+
+bool cPluginInfosatepg::SetupParse(const char *Name, const char *Value)
+{
+ // Parse your own setup parameters and store their values.
+ if (!strcasecmp(Name,"Channel")) global->Channel=atoi(Value);
+ else if (!strcasecmp(Name,"Pid")) global->Pid=atoi(Value);
+ else if (!strcasecmp(Name,"WaitTime")) global->WaitTime=atoi(Value);
+ else if (!strcasecmp(Name,"EventTimeDiff")) global->EventTimeDiff=60*atoi(Value);
+ else if (!strncasecmp(Name,"Channel",7))
+ {
+ if (strlen(Name)<10) return false;
+ tChannelID ChannelID=tChannelID::FromString(&Name[8]);
+ if (ChannelID==tChannelID::InvalidID) return false;
+ global->AddChannel(ChannelID,atoi(Value));
+ }
+ else return false;
+ return true;
+}
+
+bool cPluginInfosatepg::Service(const char *Id, void *Data)
+{
+ // Handle custom service requests from other plugins
+ return false;
+}
+
+const char **cPluginInfosatepg::SVDRPHelpPages(void)
+{
+ // Returns help text for SVDRP
+ static const char *HelpPages[] =
+ {
+ "STATE\n"
+ " Return actual state of the plugin",
+ NULL
+ };
+ return HelpPages;
+}
+
+cString cPluginInfosatepg::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
+{
+ // Process SVDRP commands
+ char *output=NULL;
+ if (!strcasecmp(Command,"STATE"))
+ {
+ int day,month;
+ asprintf(&output,"InfosatEPG state:\n");
+ if (global->isLocked(&day,&month))
+ asprintf(&output,"%s Locked: yes (%02i.%02i)",output,day,month);
+ else
+ asprintf(&output,"%s Locked: no",output);
+ asprintf(&output,"%s Switched: %s\n",output,global->isSwitched() ? "yes" : "no");
+ for (int mac=EPG_FIRST_DAY_MAC; mac<=EPG_LAST_DAY_MAC; mac++)
+ {
+ asprintf(&output,"%s Day %i (%02i.%02i.): %3i%% %s\n",
+ output,mac,global->Infosatdata[mac].Day(),global->Infosatdata[mac].Month(),
+ global->Infosatdata[mac].ReceivedPercent(),
+ global->Infosatdata[mac].wasProcessed() ? "processed" : "");
+ }
+ }
+ return output;
+}
+
+VDRPLUGINCREATOR(cPluginInfosatepg); // Don't touch this!
diff --git a/infosatepg.h b/infosatepg.h
new file mode 100644
index 0000000..1f6c22c
--- /dev/null
+++ b/infosatepg.h
@@ -0,0 +1,46 @@
+/*
+ * infosatepg.h: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#ifndef __infosatepg_h_
+#define __infosatepg_h_
+
+#include "global.h"
+#include "status.h"
+
+static const char *VERSION = "0.0.5";
+static const char *DESCRIPTION = trNOOP("Read EPG info from infosat");
+
+class cPluginInfosatepg : public cPlugin {
+private:
+ // Add any member variables or functions you may need here.
+ cGlobalInfosatepg *global;
+ cStatusInfosatepg *statusMonitor;
+public:
+ cPluginInfosatepg(void);
+ virtual ~cPluginInfosatepg();
+ virtual const char *Version(void) { return VERSION; }
+ virtual const char *Description(void) { return tr(DESCRIPTION); }
+ virtual const char *CommandLineHelp(void);
+ virtual bool ProcessArgs(int argc, char *argv[]);
+ virtual bool Initialize(void);
+ virtual bool Start(void);
+ virtual void Stop(void);
+ virtual void Housekeeping(void);
+ virtual void MainThreadHook(void);
+ virtual cString Active(void);
+ virtual time_t WakeupTime(void);
+ virtual const char *MainMenuEntry(void) { return NULL; }
+ virtual cOsdObject *MainMenuAction(void);
+ virtual cMenuSetupPage *SetupMenu(void);
+ virtual bool SetupParse(const char *Name, const char *Value);
+ virtual bool Service(const char *Id, void *Data = NULL);
+ virtual const char **SVDRPHelpPages(void);
+ virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
+ };
+
+#endif
diff --git a/po/de_DE.po b/po/de_DE.po
new file mode 100644
index 0000000..896e7be
--- /dev/null
+++ b/po/de_DE.po
@@ -0,0 +1,61 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the infosatepg package.
+# Jochen Dolze <infosatepg@dolze.de>, 2008
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vdr-1.6.0\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2008-12-10 23:03+0100\n"
+"PO-Revision-Date: 2008-05-02 16:20+0200\n"
+"Last-Translator: Jochen Dolze <infosatepg@dolze.de>\n"
+"Language-Team: <vdr@linuxtv.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Infosat channellist available"
+msgstr "Infosat Kanalliste verfügbar"
+
+msgid "Scan parameter"
+msgstr "Scan Parameter"
+
+msgid "Channel"
+msgstr "Kanal"
+
+msgid "Pid"
+msgstr "Pid"
+
+msgid "Options"
+msgstr "Optionen"
+
+msgid "WaitTime [s]"
+msgstr "Wartezeit [s]"
+
+msgid "Event TimeDiff [min]"
+msgstr "Zeitdifferenz Ereignis [min]"
+
+msgid "Infosat channels"
+msgstr "Infosat Kanäle"
+
+msgid "no"
+msgstr "nein"
+
+msgid "short text"
+msgstr "Kurztext"
+
+msgid "short/long text"
+msgstr "Kurz-/Langtext"
+
+msgid "short text/extEPG"
+msgstr "Kurztext/erwEPG"
+
+msgid "intelligent"
+msgstr "intelligent"
+
+msgid "complete"
+msgstr "komplett"
+
+msgid "Read EPG info from infosat"
+msgstr "Liest EPG infos von Infosat"
diff --git a/process.cpp b/process.cpp
new file mode 100644
index 0000000..47d5563
--- /dev/null
+++ b/process.cpp
@@ -0,0 +1,598 @@
+/*
+ * process.cpp: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <vdr/epg.h>
+#include <vdr/tools.h>
+#include <vdr/skins.h>
+#include <ctype.h>
+#include "process.h"
+#include "readline.h"
+
+// --- cInfosatevent
+cInfosatevent::cInfosatevent()
+{
+ title = NULL;
+ shortText = NULL;
+ description = NULL;
+ announcement=NULL;
+ country=NULL;
+ genre=NULL;
+ original=NULL;
+ year=-1;
+ fsk=-1;
+ category=-1;
+ startTime = 0;
+ duration = 0;
+}
+
+cInfosatevent::~cInfosatevent()
+{
+ free(title);
+ free(shortText);
+ free(description);
+ free(announcement);
+ free(country);
+ free(genre);
+ free(original);
+}
+
+void cInfosatevent::SetOriginal(const char *Original)
+{
+ original = strcpyrealloc(original, Original);
+}
+
+void cInfosatevent::SetGenre(const char *Genre)
+{
+ genre = strcpyrealloc(genre, Genre);
+}
+
+void cInfosatevent::SetCountry(const char *Country)
+{
+ country = strcpyrealloc(country, Country);
+}
+
+void cInfosatevent::SetAnnouncement(const char *Announcement)
+{
+ announcement = strcpyrealloc(announcement, Announcement);
+}
+
+void cInfosatevent::SetTitle(const char *Title)
+{
+ title = strcpyrealloc(title, Title);
+}
+
+void cInfosatevent::SetShortText(const char *ShortText)
+{
+ shortText = strcpyrealloc(shortText, ShortText);
+}
+
+void cInfosatevent::SetDescription(const char *Description)
+{
+ description = strcpyrealloc(description, Description);
+}
+
+const char *cInfosatevent::Description(const char *oldDescription)
+{
+ // Add Category:, Genre:, Year:, Country:, Originaltitle:, FSK: , Rating: [if available] ...
+ /*
+ char fmt[100];
+ char *descr;
+
+ if (oldDescription) {
+ descr=(char *) oldDescription;
+ char *extEPG=strstr(descr,"\n\n");
+ if (extEPG) *extEPG=0;
+ } else {
+ descr=description;
+ }
+
+ descr=strcatrealloc(descr,"\n\n");
+
+ if (category!=-1) {
+ descr=strcatrealloc(descr,"Category: ");
+ descr=strcatrealloc(descr,Category());
+ descr=strcatrealloc(descr,"\n");
+ }
+ if (genre) {
+ descr=strcatrealloc(descr,"Genre: ");
+ descr=strcatrealloc(descr,Genre());
+ descr=strcatrealloc(descr,"\n");
+ }
+ if (year!=-1) {
+ strncat(fmt,"Year: %i\n",9);
+ }
+ if (country) {
+ descr=strcatrealloc(descr,"Country: ");
+ descr=strcatrealloc(descr,Country());
+ descr=strcatrealloc(descr,"\n");
+ }
+ if (original) {
+ descr=strcatrealloc(descr,"Originaltitle: ");
+ descr=strcatrealloc(descr,Original());
+ descr=strcatrealloc(descr,"\n");
+ }
+ if (fsk!=-1) {
+ strncat(fmt,"FSK: %i\n",8);
+ }
+ if (announcement) {
+ descr=strcatrealloc(descr,"Rating: ");
+ descr=strcatrealloc(descr,Announcement());
+ descr=strcatrealloc(descr,"\n");
+ }
+
+ */
+ return (const char*) description;
+}
+
+// --- cProcessInfosatepg
+cProcessInfosatepg::cProcessInfosatepg(int Mac, cGlobalInfosatepg *Global)
+{
+ global=Global;
+
+ FILE *f;
+ const char *file = global->Infosatdata[Mac].GetFile();
+ f=fopen(file,"r");
+ if (f)
+ {
+ if (ParseInfosatepg(f))
+ {
+ Global->Infosatdata[Mac].SetProcessed();
+ }
+ else
+ {
+ esyslog("infosatepg: failed to get writelock while parsing %s",global->Infosatdata[Mac].GetFile());
+ }
+ fclose(f);
+ }
+}
+
+cEvent *cProcessInfosatepg::SearchEvent(cSchedule* Schedule, cInfosatevent *iEvent)
+{
+ cEvent *f=NULL;
+ int maxdiff=MAX_EVENTTIMEDIFF*60;
+
+ for (cEvent *p = Schedule->Events()->First(); p; p = Schedule->Events()->Next(p))
+ {
+ if (!strcmp(p->Title(),iEvent->Title()))
+ {
+ // found event with same title
+ int diff=abs((int) difftime(p->StartTime(),iEvent->StartTime()));
+ if (diff<=global->EventTimeDiff)
+ {
+ if (diff<maxdiff)
+ {
+ f=p;
+ maxdiff=diff;
+ }
+ }
+ }
+ }
+ return f;
+}
+
+bool cProcessInfosatepg::AddInfosatEvent(cChannel *channel, cInfosatevent *iEvent)
+{
+ if ((!channel) || (!iEvent)) return true;
+ if (iEvent->GetEventUse()==USE_NOTHING) return true; // this should never happen!
+ if (iEvent->StartTime()<time(NULL)) return true; // don't deal with old events
+ if (iEvent->StartTime()>(time(NULL)+86400)) return true; // don't deal with events to far in the future
+
+ cSchedulesLock SchedulesLock(true,2000); // to be safe ;)
+ const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
+ if (!Schedules) return false; // No write lock -> try later!
+ cSchedule* Schedule = (cSchedule *) Schedules->GetSchedule(channel,true);
+ if (!Schedule) return true;
+
+ time_t start;
+
+ const cEvent *lastEvent=Schedule->Events()->Last();
+ if ((lastEvent) && (iEvent->StartTime()<lastEvent->EndTime()))
+ {
+ // try to find, 1st with EventID
+ cEvent *Event = (cEvent *) Schedule->GetEvent(iEvent->EventID());
+ // 2nd with StartTime +/- WaitTime
+ if (!Event) Event= (cEvent *) SearchEvent(Schedule,iEvent);
+ if (!Event) return true; // just bail out with ok
+
+ start=iEvent->StartTime();
+ dsyslog("infosatepg: ievent %s [%s]", iEvent->Title(),ctime(&start));
+
+ // change existing event
+ Event->SetShortText(iEvent->ShortText());
+ if (iEvent->GetEventUse()==USE_SHORTLONGTEXT)
+ {
+ Event->SetDescription(iEvent->Description(NULL));
+ }
+ if (iEvent->GetEventUse()==USE_SHORTTEXTEPG)
+ {
+ Event->SetDescription(iEvent->Description(Event->Description()));
+ }
+ if (iEvent->GetEventUse()==USE_INTELLIGENT)
+ {
+ if (!Event->Description() || (!iEvent->Description(NULL)))
+ {
+ Event->SetDescription(iEvent->Description(NULL));
+ }
+ else
+ {
+ if (strlen(iEvent->Description(NULL))>strlen(Event->Description()))
+ {
+ Event->SetDescription(iEvent->Description(NULL));
+ }
+ }
+ }
+ Event->SetTableID(0);
+ Event->SetSeen();
+ start=Event->StartTime();
+ dsyslog("infosatepg: changed event %s [%s]",Event->Title(),ctime(&start));
+ }
+ else
+ {
+ // we are beyond the last event, so just add (if we should)
+ if (iEvent->GetEventUse()!=USE_ALL) return true;
+ start=iEvent->StartTime();
+ cEvent *Event = new cEvent(iEvent->EventID());
+ if (!Event) return true;
+ Event->SetTitle(iEvent->Title());
+ Event->SetShortText(iEvent->ShortText());
+ Event->SetDescription(iEvent->Description(NULL));
+ Event->SetStartTime(iEvent->StartTime());
+ Event->SetDuration(iEvent->Duration());
+ Event->SetVersion(0);
+ start=iEvent->StartTime();
+ dsyslog("infosatepg: adding new event %s [%s]",iEvent->Title(),ctime(&start));
+ Schedule->AddEvent(Event);
+ }
+
+ return true;
+}
+
+cChannel *cProcessInfosatepg::GetInfosatChannel(int frequency, int sid)
+{
+ cChannel *chan;
+ int source = cSource::FromString("S19.2E"); // only from astra 19.2E
+
+ for (int i=0; i<=Channels.MaxNumber(); i++)
+ {
+ chan = Channels.GetByNumber(i,0);
+ if (chan)
+ {
+ if (chan->Source()!=source) continue;
+ if (chan->Sid()!=sid) continue;
+
+ if ((chan->Frequency()==frequency) || (chan->Frequency()+1==frequency) ||
+ (chan->Frequency()-1==frequency))
+ {
+ return chan;
+ }
+ }
+ }
+ return NULL;
+}
+
+bool cProcessInfosatepg::CheckOriginal(char *s,cInfosatevent *iEvent,cCharSetConv *conv)
+{
+ char *pOT,*pEOT;
+ pOT=strchr(s,'(');
+ if (!pOT) return false;
+ pEOT=strrchr(pOT,')');
+ if (!pEOT) return false;
+ if (pEOT[1]!=0) return false;
+
+ *pOT=*pEOT=0;
+ *pOT++;
+ if (pOT[-1]==' ') pOT[-1]=0;
+ // check some things
+ if (!strcmp(pOT,"TM")) return false;
+ char *endp=NULL;
+ long int ret =strtol(pOT,&endp,10);
+ if ((ret!=0) && (*endp==0)) return false;
+ // with original title
+ iEvent->SetOriginal(conv->Convert(pOT));
+ return true;
+}
+
+bool cProcessInfosatepg::CheckAnnouncement(char *s,cInfosatevent *iEvent)
+{
+ bool ret=true;
+ if ((strlen(s)==16) && (!strcmp(s,"Erstausstrahlung")))
+ {
+ iEvent->SetAnnouncement("Erstausstrahlung");
+ }
+ else if ((strlen(s)==20) && (!strcmp(s,"Deutschland-Premiere")))
+ {
+ iEvent->SetAnnouncement("Deutschland-Premiere");
+ }
+ else if ((strlen(s)>=16) && (!strncmp(s,"Free-TV-Premiere",16)))
+ {
+ iEvent->SetAnnouncement("Free-TV-Premiere!");
+ }
+ else if ((strlen(s)>=9) && (!strncmp(s,"Highlight",9)))
+ {
+ iEvent->SetAnnouncement("Tipp");
+ }
+ else ret=false;
+ return ret;
+}
+
+bool cProcessInfosatepg::ParseInfosatepg(FILE *f)
+{
+ char *s,tag;
+ int fields,index;
+ size_t size;
+ time_t oldstart;
+ bool ignore=true;
+ bool abort=false;
+ struct tm tm;
+ int ieventnr=1;
+ cChannel *chan=NULL;
+ cInfosatevent *ievent=NULL;
+#if VDRVERSNUM < 10701
+ cCharSetConv *conv = new cCharSetConv("ISO-8859-1",cCharSetConv::SystemCharacterTable() ?
+ cCharSetConv::SystemCharacterTable() : "UTF-8");
+#else
+ cCharSetConv *conv = new cCharSetConv("ISO-8859-1",NULL);
+#endif
+
+ cReadLineInfosatepg ReadLine;
+ while ((s=ReadLine.Read(f,&size))!=NULL)
+ {
+ if (size<3) continue;
+ if (isdigit(s[0]))
+ {
+ if (ievent)
+ {
+ int category,fsk;
+ fields=sscanf(s,"%d %d",&category,&fsk);
+ if (fields==1) ievent->SetCategory(category);
+ if (fields==2)
+ {
+ ievent->SetCategory(category);
+ ievent->SetFSK(fsk);
+ }
+ }
+ continue;
+ }
+
+ s++;
+ tag=*s;
+ s+=2;
+ switch (tag)
+ {
+ case 'P':
+ // contains program (schedule)
+ ignore=true;
+ int frequency,sid,day,month,year,hour,minute;
+ fields=sscanf(s,"%*[^(](%*[^,],%d,%d) %d.%d.%d %*s %*s %d:%d",
+ &frequency,&sid,&day,&month,&year,&hour,&minute);
+ if (fields==7)
+ {
+ // got all fields
+ chan=GetInfosatChannel(frequency,sid);
+ if (chan)
+ {
+ if (!global->ChannelExists(chan->GetChannelID(),&index))
+ {
+ if (!global->InfosatChannels())
+ {
+ // Send message
+ Skins.QueueMessage(mtInfo,tr("Infosat channellist available"));
+ }
+ // Channel is not in global list->add
+ global->AddChannel(chan->GetChannelID(),USE_NOTHING);
+ }
+ else
+ {
+ if (global->GetChannelUse(index)!=USE_NOTHING)
+ {
+ memset(&tm,0,sizeof(tm));
+ tm.tm_sec=0;
+ tm.tm_min=minute;
+ tm.tm_hour=hour;
+ tm.tm_mday=day;
+ tm.tm_mon=month-1;
+ tm.tm_year=year-1900;
+ tm.tm_isdst=-1;
+ oldstart=mktime(&tm);
+ dsyslog("infosatepg: using '%s'",s);
+ dsyslog("infosatepg: start on %02i.%02i.%04i %02i:%02i",tm.tm_mday,tm.tm_mon+1,tm.tm_year+1900,
+ tm.tm_hour,tm.tm_min);
+ ignore=false;
+ ieventnr=1;
+ }
+ }
+ }
+ }
+ break;
+ case 'E':
+ // contains event / title
+ if (ignore) continue;
+ if (ievent)
+ {
+ // There was an event without long description -> add
+ if (!AddInfosatEvent(chan,ievent)) abort=true;
+ oldstart=ievent->StartTime();
+ delete ievent; // delete old event
+ ievent =NULL;
+ }
+ else
+ {
+ oldstart=(time_t) -1;
+ }
+ int shour,sminute;
+ char *title;
+ fields=sscanf(s,"%d:%d %a[^^]",&shour,&sminute,&title);
+ if (fields==3)
+ {
+ if (!ievent) ievent = new cInfosatevent;
+ tm.tm_hour=shour;
+ tm.tm_min=sminute;
+ tm.tm_isdst=-1;
+ time_t start=mktime(&tm);
+ if ((oldstart!=(time_t) -1) && (difftime(start,oldstart)<0))
+ {
+ // last ievent was yesterday
+ tm.tm_isdst=-1;
+ tm.tm_mday++;
+ start=mktime(&tm);
+ }
+ ievent->SetStartTime(start);
+ ievent->SetTitle(conv->Convert(title));
+ free(title);
+ ievent->SetEventUse(global->GetChannelUse(index));
+ ievent->SetEventID(DoSum(ieventnr++,ievent->Title(),strlen(ievent->Title())));
+ }
+ else
+ {
+ dsyslog("infosatepg: ERROR sscanf failed, just %i fields [%s]", fields,s);
+ }
+ break;
+
+ case 'S':
+ if (ignore) continue;
+ if (!ievent) continue;
+ // contains:
+ // short description (,maybe special announcement)<8A>
+ // Genre (,maybe Country and Year), Duration (sometimes missing)
+ char *p8A,*pSA;
+ p8A=strchr(s,0x8A);
+ if (p8A)
+ {
+ *p8A=0;
+ // check for special announcements:
+ // Erstausstrahlung
+ // Deutschland-Premiere
+ // Free-TV-Premiere
+ // Highlight
+ pSA=strrchr(s,',');
+ if (pSA)
+ {
+ if (CheckAnnouncement(pSA+2,ievent))
+ {
+ // announcement was added to short description
+ *pSA=0;
+ }
+ CheckOriginal(s,ievent,conv);
+ ievent->SetShortText(conv->Convert(s));
+ }
+ else
+ {
+ if (!CheckAnnouncement(s,ievent))
+ {
+ CheckOriginal(s,ievent,conv);
+ ievent->SetShortText(conv->Convert(s));
+ }
+ }
+ s=++p8A;
+ }
+ char *pDU;
+ pDU=strrchr(s,',');
+ if (pDU)
+ {
+ *pDU=0;
+ // with genre
+ if (CheckAnnouncement(s,ievent))
+ {
+ char *tp8A;
+ tp8A=strchr(s,0x8A);
+ if (tp8A) s=++tp8A;
+ }
+ char *pCY;
+ pCY=strchr(s,',');
+ if (pCY)
+ {
+ // with country or year
+ *pCY=0;
+ pCY+=2;
+ if (isdigit(*pCY))
+ {
+ // just year (checked)
+ ievent->SetYear(atoi(pCY));
+ }
+ else
+ {
+ char *pSP;
+ pSP=strrchr(pCY,' ');
+ if (pSP)
+ {
+ *pSP=0;
+ pSP++;
+ // country and year (check!!)
+ int year = atoi(pSP);
+ if (year!=0) ievent->SetYear(year);
+ ievent->SetCountry(conv->Convert(pCY));
+ }
+ else
+ {
+ // just country
+ ievent->SetCountry(conv->Convert(pCY));
+ }
+ }
+ }
+ ievent->SetGenre(conv->Convert(s));
+ s=++pDU;
+ }
+ int len;
+ len=strlen(s);
+ if ((s[len-1]=='.') && (s[len-2]=='n') && (s[len-3]=='i') && (s[len-4]=='M'))
+ {
+ // Duration
+ ievent->SetDuration(60*atoi(s));
+ }
+ break;
+
+ case 'L':
+ // contains description
+ if (ignore) continue;
+ if (!ievent) continue;
+ strreplace(s,0x8A,'\n');
+ ievent->SetDescription(conv->Convert(s));
+ if (!AddInfosatEvent(chan,ievent)) abort=true;
+ oldstart=ievent->StartTime();
+ delete ievent;
+ ievent=NULL;
+ break;
+ case 'Q':
+ if (ignore) continue;
+ if (ievent)
+ {
+ if (!AddInfosatEvent(chan,ievent)) abort=true;
+ delete ievent;
+ ievent=NULL;
+ }
+ default:
+ continue;
+ }
+
+ if (abort) break;
+
+ }
+ delete conv;
+ return (!abort);
+}
+
+u_long cProcessInfosatepg::DoSum(u_long sum, const char *buf, int nBytes)
+{
+ int nleft=nBytes;
+ u_short *w = (u_short*)buf;
+
+ while (nleft > 1)
+ {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ if (nleft == 1)
+ {
+ u_short answer = 0;
+ *(u_char*)(&answer) = *(u_char*)w;
+ sum += answer;
+ }
+ return sum;
+}
diff --git a/process.h b/process.h
new file mode 100644
index 0000000..0edc68b
--- /dev/null
+++ b/process.h
@@ -0,0 +1,83 @@
+/*
+ * process.h: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#ifndef __process_h_
+#define __process_h_
+
+#include "global.h"
+
+// --- cInfosatevent
+class cInfosatevent
+{
+private:
+ int duration;
+ time_t startTime;
+ char *title;
+ char *shortText;
+ char *description;
+ char *announcement;
+ char *country;
+ char *genre;
+ char *original;
+ int category;
+ int fsk;
+ int year;
+ int usage;
+ tEventID eventID;
+public:
+ cInfosatevent();
+ ~cInfosatevent();
+ void SetTitle(const char *Title);
+ void SetShortText(const char *ShortText);
+ void SetDescription(const char *Description);
+ void SetStartTime(time_t StartTime) { startTime=StartTime; }
+ void SetDuration(int Duration) { duration=Duration; }
+ void SetEventUse(int Usage) { usage=Usage; }
+ void SetYear(int Year) { year=Year; }
+ void SetEventID(tEventID EventID) { eventID=EventID; }
+ void SetCategory(int Category) { category=Category; }
+ void SetFSK(int FSK) { fsk=FSK; }
+
+ void SetAnnouncement(const char *Announcement);
+ void SetCountry(const char *Country);
+ void SetGenre(const char *Genre);
+ void SetOriginal(const char *Original);
+ const char *Description(const char *oldDescription);
+
+ const char *Title(void) const { return title; }
+ const char *ShortText(void) const { return shortText; }
+ const char *Announcement(void) const { return announcement; }
+ const char *Genre(void) const { return genre; }
+ const char *Country(void) const { return country; }
+ const char *Original(void) const { return original; }
+ int Year(void) const { return year; }
+ int Duration(void) const { return duration; }
+ int FSK(void) const { return fsk; }
+ int Category(void) const { return category; }
+ time_t StartTime(void) const { return startTime; }
+ int GetEventUse() { return usage; }
+ tEventID EventID(void) const { return eventID; }
+};
+
+// --- cProcessInfosatepg
+class cProcessInfosatepg
+{
+private:
+ cGlobalInfosatepg *global;
+ bool AddInfosatEvent(cChannel *channel, cInfosatevent *iEvent);
+ bool CheckOriginal(char *s,cInfosatevent *iEvent,cCharSetConv *conv);
+ bool CheckAnnouncement(char *s,cInfosatevent *iEvent);
+ bool ParseInfosatepg(FILE *f);
+ cChannel *GetInfosatChannel(int frequency, int sid);
+ u_long DoSum(u_long sum, const char *buf, int nBytes);
+ cEvent *SearchEvent(cSchedule* Schedule, cInfosatevent *iEvent);
+public:
+ cProcessInfosatepg(int Mac, cGlobalInfosatepg *Global);
+};
+
+#endif
diff --git a/readline.cpp b/readline.cpp
new file mode 100644
index 0000000..f13852e
--- /dev/null
+++ b/readline.cpp
@@ -0,0 +1,70 @@
+/*
+ * readline.cpp: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "readline.h"
+
+// --- cReadLineInfosatepg ---------------------------------------------------
+
+cReadLineInfosatepg::cReadLineInfosatepg(void)
+{
+ buffer = NULL;
+}
+
+cReadLineInfosatepg::~cReadLineInfosatepg()
+{
+ free(buffer);
+}
+
+char *cReadLineInfosatepg::Read(FILE *f,size_t *size)
+{
+ free(buffer); buffer=NULL;
+ if ((!size) || (!f)) return NULL;
+ bool ext=false;
+ *size=0;
+ do
+ {
+ char *tempbuffer=NULL;
+ size_t tempsize=0;
+
+ ext=false;
+ int n = getline(&tempbuffer, &tempsize, f);
+ if (n > 0)
+ {
+ if (tempbuffer[n-1] == '\n')
+ {
+ n--;
+ tempbuffer[n] = 0;
+ if (n > 0)
+ {
+ if (tempbuffer[n-1] == '\r')
+ n--;
+ tempbuffer[n] = 0;
+ }
+ }
+ if (n>0)
+ {
+ if (tempbuffer[n-1] == '\\')
+ {
+ n--;
+ tempbuffer[n]=0;
+ ext=true;
+ }
+ }
+
+ buffer=(char*) realloc(buffer,*size+(n+1));
+ snprintf(&buffer[*size],n+1,tempbuffer);
+ free(tempbuffer);
+ *size+=n;
+ }
+ }
+ while (ext==true);
+
+ return buffer;
+}
diff --git a/readline.h b/readline.h
new file mode 100644
index 0000000..ab674ad
--- /dev/null
+++ b/readline.h
@@ -0,0 +1,23 @@
+/*
+ * readline.h: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#ifndef __readline_h_
+#define __readline_h_
+
+#include <sys/types.h>
+
+class cReadLineInfosatepg {
+private:
+ char *buffer;
+public:
+ cReadLineInfosatepg(void);
+ ~cReadLineInfosatepg();
+ char *Read(FILE *f,size_t *size);
+ };
+
+#endif
diff --git a/setup.cpp b/setup.cpp
new file mode 100644
index 0000000..8e5a292
--- /dev/null
+++ b/setup.cpp
@@ -0,0 +1,149 @@
+/*
+ * setup.cpp: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#include "setup.h"
+
+// --- cMenuSetupInfosatepg
+cMenuSetupInfosatepg::cMenuSetupInfosatepg(cGlobalInfosatepg *Global)
+{
+ global=Global;
+
+ newChannel = global->Channel;
+ newPid = global->Pid;
+ newWaitTime = global->WaitTime;
+ newEventTimeDiff=(int) (global->EventTimeDiff/60);
+
+ Add(NewTitle(tr("Scan parameter")));
+ cOsdItem *firstItem = new cMenuEditIntItem( tr("Channel"), &newChannel,1,Channels.MaxNumber());
+ Add(firstItem);
+ Add(new cMenuEditIntItem( tr("Pid"), &newPid,1,8191));
+
+ Add(NewTitle(tr("Options")));
+ Add(new cMenuEditIntItem( tr("WaitTime [s]"), &newWaitTime,MIN_WAITTIME,MAX_WAITTIME));
+ Add(new cMenuEditIntItem( tr("Event TimeDiff [min]"), &newEventTimeDiff,
+ MIN_EVENTTIMEDIFF,MAX_EVENTTIMEDIFF));
+
+ if (global->InfosatChannels())
+ {
+ Add(NewTitle(tr("Infosat channels")),true);
+ chanCurrent=Current()+1;
+ SetCurrent(firstItem);
+
+ for (int i=0; i<global->InfosatChannels(); i++)
+ {
+ cChannel *chan = Channels.GetByChannelID(global->GetChannelID(i));
+ if (!chan) continue;
+ Add(new cOsdItem(chan->Name()));
+ }
+ }
+}
+
+cOsdItem *cMenuSetupInfosatepg::NewTitle(const char *s)
+{
+ char *str;
+ asprintf(&str,"---- %s ----", s);
+ cOsdItem *tmp = new cOsdItem(str);
+ tmp->SetSelectable(false);
+ free(str);
+ return tmp;
+}
+
+void cMenuSetupInfosatepg::Store(void)
+{
+ bool bReprocess=false;
+
+ if (global->EventTimeDiff!=(60*newEventTimeDiff)) bReprocess=true;
+
+ SetupStore("Channel", global->Channel = newChannel);
+ SetupStore("Pid", global->Pid = newPid);
+ SetupStore("WaitTime", global->WaitTime = newWaitTime);
+ SetupStore("EventTimeDiff", newEventTimeDiff);
+ global->EventTimeDiff = 60*newEventTimeDiff;
+
+ if (bReprocess) global->ResetProcessedFlags();
+}
+
+eOSState cMenuSetupInfosatepg::Edit()
+{
+ if (HasSubMenu() || Count()==0)
+ return osContinue;
+ if (Current()>=chanCurrent)
+ {
+ int chanIndex=Current()-chanCurrent;
+ if (chanIndex<global->InfosatChannels())
+ return AddSubMenu(new cMenuSetupChannelMenu(global,chanIndex));
+ else
+ return osContinue;
+ }
+ else
+ return osContinue;
+}
+
+eOSState cMenuSetupInfosatepg::ProcessKey(eKeys Key)
+{
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ switch (state)
+ {
+ default:
+ if (state==osUnknown)
+ {
+ switch (Key)
+ {
+ case kOk:
+ return Edit();
+ default:
+ break;
+ }
+ }
+ }
+ return state;
+}
+
+cMenuSetupChannelMenu::cMenuSetupChannelMenu(cGlobalInfosatepg *Global, int Index)
+{
+ SetPlugin(cPluginManager::GetPlugin(PLUGIN_NAME_I18N));
+ global=Global;
+ index=Index;
+
+ ChannelUseText[0]=tr("no");
+ ChannelUseText[1]=tr("short text");
+ ChannelUseText[2]=tr("short/long text");
+ ChannelUseText[3]=tr("short text/extEPG");
+ ChannelUseText[4]=tr("intelligent");
+ ChannelUseText[5]=tr("complete");
+
+ newChannelUse=global->GetChannelUse(index);
+ if (newChannelUse<0) newChannelUse=USE_NOTHING; // to be safe!
+
+ channel = Channels.GetByChannelID(global->GetChannelID(index));
+
+ char *str;
+ asprintf(&str,"---- %s ----", channel->Name());
+ Add(new cOsdItem(str,osUnknown,false));
+ free(str);
+
+ Add(new cMenuEditStraItem("Usage",&newChannelUse,
+ sizeof(ChannelUseText)/sizeof(const char *),ChannelUseText));
+
+}
+
+void cMenuSetupChannelMenu::Store(void)
+{
+ bool bReprocess=false;
+
+ if (!channel) return;
+ cString ChannelID = channel->GetChannelID().ToString();
+ char *name;
+ asprintf(&name,"Channel-%s",*ChannelID);
+ if (!name) return;
+ if (global->SetChannelUse(index,newChannelUse)) bReprocess=true;
+ SetupStore(name,newChannelUse);
+ free(name);
+ if (bReprocess) global->ResetProcessedFlags();
+}
diff --git a/setup.h b/setup.h
new file mode 100644
index 0000000..3206e49
--- /dev/null
+++ b/setup.h
@@ -0,0 +1,49 @@
+/*
+ * setup.h: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#ifndef __setup_h_
+#define __setup_h_
+
+#include <vdr/plugin.h>
+#include <vdr/menuitems.h>
+#include "global.h"
+
+class cMenuSetupInfosatepg : public cMenuSetupPage
+{
+private:
+ cGlobalInfosatepg *global;
+ int newChannel;
+ int newWaitTime;
+ int newEventTimeDiff;
+ int newPid;
+ int chanCurrent;
+protected:
+ virtual void Store(void);
+private:
+ cOsdItem *NewTitle(const char *s);
+ eOSState Edit(void);
+public:
+ cMenuSetupInfosatepg(cGlobalInfosatepg *Global);
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+class cMenuSetupChannelMenu : public cMenuSetupPage
+{
+private:
+ cGlobalInfosatepg *global;
+ const char * ChannelUseText[6];
+ int newChannelUse;
+ int index;
+ cChannel *channel;
+protected:
+ virtual void Store(void);
+public:
+ cMenuSetupChannelMenu(cGlobalInfosatepg *Global, int Index);
+};
+
+#endif
diff --git a/status.cpp b/status.cpp
new file mode 100644
index 0000000..b540f74
--- /dev/null
+++ b/status.cpp
@@ -0,0 +1,63 @@
+/*
+ * status.cpp: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#include "status.h"
+
+cStatusInfosatepg::cStatusInfosatepg(cGlobalInfosatepg *Global)
+{
+ global = Global;
+ myFilter=new cFilterInfosatepg(global);
+ myFilterDevice=NULL;
+}
+
+cStatusInfosatepg::~cStatusInfosatepg(void)
+{
+ if (myFilterDevice) myFilterDevice->Detach(myFilter);
+ if (myFilter) delete myFilter;
+}
+
+void cStatusInfosatepg::ChannelSwitch(const cDevice *Device, int ChannelNumber)
+{
+ bool bAddFilter=false;
+
+ // just add filter if we aren't locked
+ if ((ChannelNumber==global->Channel) && (!global->isLocked())) bAddFilter=true;
+
+ if (bAddFilter)
+ {
+
+ if ((myFilterDevice) && (myFilter))
+ {
+ if (myFilterDevice==Device) return; // already attached -> bail out
+ dsyslog("infosatepg: detach previously attached filter");
+ myFilterDevice->Detach(myFilter);
+ }
+
+ myFilterDevice = Device->GetDevice(Device->DeviceNumber());
+ if (!myFilterDevice) return;
+
+ dsyslog("switching device %i to channel %i (infosatepg)",
+ Device->DeviceNumber()+1,ChannelNumber);
+ myFilterDevice->AttachFilter(myFilter);
+ global->SetSwitched(true);
+ }
+ else
+ {
+ if (myFilterDevice)
+ {
+ if (Device==myFilterDevice)
+ {
+ dsyslog("infosatepg: detach filter");
+ myFilterDevice->Detach(myFilter);
+ myFilterDevice=NULL;
+ global->SetTimer();
+ global->SetSwitched(false);
+ }
+ }
+ }
+}
diff --git a/status.h b/status.h
new file mode 100644
index 0000000..9fd7043
--- /dev/null
+++ b/status.h
@@ -0,0 +1,29 @@
+/*
+ * status.h: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+#ifndef __status_h_
+#define __status_h_
+
+#include <vdr/status.h>
+
+#include "filter.h"
+#include "global.h"
+
+// --- cStatusInfosatepg
+class cStatusInfosatepg : public cStatus {
+private:
+ cFilterInfosatepg *myFilter;
+ cDevice *myFilterDevice;
+ cGlobalInfosatepg *global;
+protected:
+ virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
+public:
+ cStatusInfosatepg(cGlobalInfosatepg *Global);
+ virtual ~cStatusInfosatepg(void);
+ };
+
+#endif