/*
 * tvtv.c: TVTV plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 *
 */

#include <string>
#include <getopt.h>
#include <stdlib.h>
#include <vdr/interface.h>
#include <vdr/plugin.h>
#include "i18n.h"
#include <sys/wait.h>
#include <unistd.h>
#include <vdr/videodir.h>
#include <ctype.h>
#include "config.h"
#include "update.h"
#include "md5tools.h"

using namespace std;


static const char *VERSION        = "0.2.13a";
static const char *DESCRIPTION    = "TVTV Timers update";
static const char *MAINMENUENTRY  = "TVTV";

cUpdate *oUpdate;

class cPluginTVTV : public cPlugin {
public:
  cPluginTVTV(void);
  virtual ~cPluginTVTV();
  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 Start(void);
  virtual void Housekeeping(void);
  virtual const char *MainMenuEntry(void) { return (TVTVConfig.show_in_mainmenu ? MAINMENUENTRY : NULL); }
  virtual cOsdMenu *MainMenuAction(void);
  virtual cMenuSetupPage *SetupMenu(void);
  virtual bool SetupParse(const char *Name, const char *Value);
  virtual void Get_Packed_String(char *sOut);
  };

// --- cMenuSetupTVTV -------------------------------------------------------

class cMenuSetupTVTV : public cMenuSetupPage {
private:
  cTVTVConfig data; 
  virtual void Setup(void);
protected:
  virtual eOSState ProcessKey(eKeys Key);
  virtual void Store(void);
public:
  cMenuSetupTVTV(void);
  };

cMenuSetupTVTV::cMenuSetupTVTV(void) {
  data = TVTVConfig;
  Setup();
}

void cMenuSetupTVTV::Setup(void) {
  int current = Current();
  
  Clear();

  Add(new cMenuEditStraItem(  tr("TVTV Server"), &data.tvtv_server, TVTVSRV_CNT, TVTV_SERVERS));
  Add(new cMenuEditStrItem(   tr("TVTV User Name"), data.username, sizeof(data.username), tr(FileNameChars)));
  Add(new cMenuEditStrItem(   tr("TVTV Password"), data.password, sizeof(data.password), tr(FileNameChars)));
  Add(new cMenuEditBoolItem(  tr("Use HTTP Proxy"), &data.useproxy));
  if (data.useproxy)
    Add(new cMenuEditStrItem( tr("  HTTP Proxy"), data.httpproxy, sizeof(data.httpproxy), tr(FileNameChars)));
  Add(new cMenuEditBoolItem(  tr("Auto Update"), &data.autoupdate));
  Add(new cMenuEditIntItem(   tr("Updatetime (min)"), &data.updatetime));
  Add(new cMenuEditBoolItem(  tr("Use Nature within File Name"), &data.usegenre));
  Add(new cMenuEditBoolItem(  tr("Use Station Name within File Name"), &data.usestation));
  Add(new cMenuEditBoolItem(  tr("Show In Main Menu"), &data.show_in_mainmenu));

// VPS was introduced with VDR 1.3.5
#if VDRVERSNUM >= 10305
  Add(new cMenuEditBoolItem( tr("Use VPS"), &data.usevps));
#endif
  
// Starting with VDR 1.3.44, the description of a recording is 
// taken from EPG. This switch decides whether or not the description
// coming from TVTV will be added as a comment to info.vdr.
#if VDRVERSNUM >= 10344
  Add(new cMenuEditBoolItem( tr("Use TVTV description in info.vdr"), &data.usetvtvdescr));
#endif

  SetCurrent(Get(current));
  Display();
}


eOSState cMenuSetupTVTV::ProcessKey(eKeys Key) {
    int olduseproxy = data.useproxy;
    eOSState state = cMenuSetupPage::ProcessKey(Key);
    if (Key != kNone && (data.useproxy != olduseproxy)) Setup();
    return state;
}

void cMenuSetupTVTV::Store(void)
{
  TVTVConfig = data;
  SetupStore("TVTVServer", TVTVConfig.tvtv_server);
  SetupStore("UserName", TVTVConfig.username);
  SetupStore("Password", TVTVConfig.password);
  SetupStore("UseProxy", TVTVConfig.useproxy);
  SetupStore("HTTPProxy", TVTVConfig.httpproxy);
  SetupStore("AutoUpdate", TVTVConfig.autoupdate);
  SetupStore("UpdateTime", TVTVConfig.updatetime);
  SetupStore("UseGenreInFName", TVTVConfig.usegenre);
  SetupStore("UseStationInFName", TVTVConfig.usestation);
  SetupStore("ShowInMainMenu", TVTVConfig.show_in_mainmenu);

// VPS was introduced with VDR 1.3.5
#if VDRVERSNUM >= 10305
  SetupStore("UseVps", TVTVConfig.usevps);
#endif	        

#if VDRVERSNUM >= 10344
  SetupStore("UseTVTVDescr", TVTVConfig.usetvtvdescr);
#endif

  if (TVTVConfig.autoupdate)
    if (oUpdate)
	oUpdate->StartUpdate();
}

// --- cPluginTVTV ----------------------------------------------------------

cPluginTVTV::cPluginTVTV(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!
    oUpdate = NULL;
}

cPluginTVTV::~cPluginTVTV()
{
  // Clean up after yourself!
    if (oUpdate)
	delete oUpdate;
}

const char *cPluginTVTV::CommandLineHelp(void)
{
  // Return a string that describes all known command line options.
  return NULL; 
}

bool cPluginTVTV::ProcessArgs(int argc, char *argv[])
{
  // Implement command line argument processing here if applicable.
  return true;
}


void cPluginTVTV::Get_Packed_String(char *sOut)
{
    char *s;
    unsigned char signature[17];
    
    asprintf(&s, "EPGSync%s%s", TVTVConfig.username, TVTVConfig.password);

    MD5_CTX ctx;
    MD5Init(&ctx);
    MD5Update(&ctx, (unsigned char *)s, strlen(s));
    MD5Final(signature, &ctx);
    signature[16] = 0;

    char aStr[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    
    char aOut[30];
    int j = 0;
	    
    aOut[16] = '\0';
		
    for (int i = 0; i < 16; i+= 3)
    {
	uint8_t x, y;
		
	x = signature[i];
	x >>= 2;
	x = x & 0x3f;
	aOut[j++] = aStr[x];
								
	y = signature[i];
	y = y & 0x3;
	y <<= 4;
									
	x = signature[i + 1];
	x >>= 4;
	x = x & 0x0f;
	x = x ^ y;
	aOut[j++] = aStr[x];
																
	if (i + 1 < 16)
	{
	    y = signature[i + 1];
	    y = y & 0x0f;
	    y <<= 2;
						    
	    // 3
	    x = signature[i + 2];
	    x = x & 0xff;
	    x >>= 6;
	    x = x ^ y;
	    aOut[j++] = aStr[x];
															    
	    // 4
	    x = signature[i + 2];
	    x &= 0x3f;
	    aOut[j++] = aStr[x];
	}
	else
	{
	    aOut[j++] = (char) 0x3d;
	    aOut[j++] = (char) 0x3d;
	}
			
	aOut[j] = '\0';
    }

    strcpy(sOut, aOut);							    
		    
    free(s);
}
				


bool cPluginTVTV::Start(void)
{
    // Start any background activities the plugin shall perform.
    RegisterI18n(Phrases);
    Get_Packed_String(sPackedString);
    isyslog("TVTV: Packed String: %s", sPackedString);
    
    oUpdate = new cUpdate();
    
    if (oUpdate && TVTVConfig.autoupdate)
	oUpdate->StartUpdate();
    
    return true;
}

void cPluginTVTV::Housekeeping(void)
{
  // Perform any cleanup or other regular tasks.
}

cOsdMenu *cPluginTVTV::MainMenuAction(void)
{
  // Perform the action when selected from the main VDR menu.
  if (oUpdate) oUpdate->StartUpdate();

  Interface->Confirm(tr("TVTV update will be started"), 1);
  
  return NULL;
}

cMenuSetupPage *cPluginTVTV::SetupMenu(void)
{
  // Return a setup menu in case the plugin supports one.
  return new cMenuSetupTVTV;
}

bool cPluginTVTV::SetupParse(const char *Name, const char *Value)
{
  // Parse your own setup parameters and store their values.

  if      (!strcasecmp(Name, "TVTVServer"))  TVTVConfig.tvtv_server = atoi(Value);
  else if (!strcasecmp(Name, "UserName"))    strcpy(TVTVConfig.username, Value);
  else if (!strcasecmp(Name, "Password"))    strcpy(TVTVConfig.password, Value);
  else if (!strcasecmp(Name, "UseProxy"))    TVTVConfig.useproxy = atoi(Value);
  else if (!strcasecmp(Name, "HTTPProxy"))   strcpy(TVTVConfig.httpproxy, Value);
  else if (!strcasecmp(Name, "AutoUpdate"))  TVTVConfig.autoupdate = atoi(Value);
  else if (!strcasecmp(Name, "UpdateTime"))  TVTVConfig.updatetime = atoi(Value);
  else if (!strcasecmp(Name, "UseGenreInFName")) TVTVConfig.usegenre = atoi(Value);
  else if (!strcasecmp(Name, "UseStationInFName")) TVTVConfig.usestation = atoi(Value);
  else if (!strcasecmp(Name, "ShowInMainMenu")) TVTVConfig.show_in_mainmenu = atoi(Value);
// VPS was introduced with VDR 1.3.5
#if VDRVERSNUM >= 10305
  else if (!strcasecmp(Name, "UseVps"))         TVTVConfig.usevps = atoi(Value);
#endif
  
#if VDRVERSNUM >= 10344
  else if (!strcasecmp(Name, "UseTVTVDescr"))   TVTVConfig.usetvtvdescr = atoi(Value);
#endif

  else
     return false;
  return true;
}

VDRPLUGINCREATOR(cPluginTVTV); // Don't touch this!

