diff options
-rw-r--r-- | COPYING | 340 | ||||
-rw-r--r-- | DELETE.ME | 0 | ||||
-rw-r--r-- | HISTORY | 31 | ||||
-rw-r--r-- | Makefile | 112 | ||||
-rw-r--r-- | README | 18 | ||||
-rw-r--r-- | filter.cpp | 187 | ||||
-rw-r--r-- | filter.h | 44 | ||||
-rw-r--r-- | global.cpp | 334 | ||||
-rw-r--r-- | global.h | 184 | ||||
-rw-r--r-- | infosatepg.cpp | 258 | ||||
-rw-r--r-- | infosatepg.h | 46 | ||||
-rw-r--r-- | po/de_DE.po | 61 | ||||
-rw-r--r-- | process.cpp | 598 | ||||
-rw-r--r-- | process.h | 83 | ||||
-rw-r--r-- | readline.cpp | 70 | ||||
-rw-r--r-- | readline.h | 23 | ||||
-rw-r--r-- | setup.cpp | 149 | ||||
-rw-r--r-- | setup.h | 49 | ||||
-rw-r--r-- | status.cpp | 63 | ||||
-rw-r--r-- | status.h | 29 |
20 files changed, 2679 insertions, 0 deletions
@@ -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 @@ -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 @@ -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(ð_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(ð_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(); +} @@ -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 |