############################################################################ # # File: TClient-lib.itcl # # Description: Outer block library for the TiVo Center client. # # $$$TIVO COPYRIGHT (Jak Mang)$$$ # ############################################################################# lappend auto_path $tcl_library/tv source $tcl_library/tv/Inc.itcl source $tcl_library/tv/StatusStrings.itcl source $tcl_library/tv/DbEnum.tcl tvsource $tcl_library/tv/CmdStr.itcl tvsource $tcl_library/tv/EndPoint.itcl tvsource $tcl_library/tv/Ident.itcl tvsource $tcl_library/tv/SwSystem.itcl tvsource $tcl_library/tv/Database.itcl tvsource $tcl_library/tv/SvrResp.itcl tvsource $tcl_library/tv/mfslib.tcl tvsource $tcl_library/tv/LogMgr.itcl tvsource $tcl_library/tv/Setup.itcl tvsource $tcl_library/tv/DataSet.itcl tvsource $tcl_library/tv/TCD411Rqst.itcl tvsource $tcl_library/tv/TCD411RespCli.itcl tvsource $tcl_library/tv/date.tcl namespace import Inc::* ######## # # SendDialupEvent # ######## proc SendDialupEvent { subtype message } { if { [string length $message] > 19 } { putlog "Message too long in SendDialupEvent: $message" set message [string range $message 0 18] } set data [binary format a20 $message] putlog "SendDialupEvent $TmkEvent::EVT_DIALUPEVENT $subtype $message" event send $TmkEvent::EVT_DIALUPEVENT $subtype $data } class TClient { inherit EndPoint variable callReason 0 variable userInitiated 1 variable commitNow 0 variable testMessage 0 variable swActivated 1 variable waitingToReboot 0 variable lastKnownState "" variable overrideStatusString "" variable activeSwName "" variable callId "UNDEFINED" variable tcdId "UNDEFINED" variable db "" variable backHaulDone 0 variable useBackupTollFree 0 variable useDefaultNumber 0 variable lastStatusDBMsg "" variable useAPG "false" # UK AltEPG: new class variables for improved daily call control # (Author: millsb, 2011-06-18) variable callDeferred 0 variable callDeferredReason "" variable realCallWaitingPrefix "" variable connectionPath "Not established" variable deferralRule "" variable diagnostics 1 variable diallingError "" variable httpLogMessage "HTTP Log:" variable callDetailsSource "" variable version "0.8 2011-08-19" constructor {} { set db [dbopen] } destructor { if {$db != ""} { dbclose $db } log $logStrm close } method login {} method init {argvlist} method getCenterID {} method getLocationID {} method getCurrentSoftware {} method getCurrentShowcases {} method lastDayForStation { stationId } method getHeadendIDList {} method processLogs {} method connectPPP {phone pppUser pppPass} method toggleLed {on} method tidyUp {} method updateStatus {msg} method getWaitingCount {} method makeKeyQueryFile {filename} # method registerNewSoftware {} method waitForTime {timestamp} method getTZ {} method getSvrInfo {code} method getCurMessages {} method getAreaCodeVer {areaCode} method doHttpCall { argObj name host port } method process411 { tcd411Resp reason} method findPhone { setup calltype} method getCurPhoneNum { setup } method setPhase { phase } method getPhase {} method initializePhase {} method sendString { msg } method getBackHaulDone {} method getTollFreeNum {curTollFreeNum} method setSvrRespRef {ref} method getRunningSwName {} method getActiveSwName {} method setActiveSwName {name} # # This method POST's the /var/log/svclog to the server method postSvcLog {} method postCommLog {} method postGenericFile {file url} # method handleDataSet {} method handleVariableDataSets {} # method CleanupDiagFiles {} method CleanupMempools {} method CleanupDataSets {} # # effects: causes a EVT_DBGC_REQUEST run and then waits for the # SUCCEEDED or FAILED message # method StartAndWaitForGc { request } # # effects: sends a EVT_DBGC_REQUEST message with this $request # idRequestor is this pid's id and idSubrequestor is $request # method SendGcRequest { request } # # Log method to support the moderated log # This method will insert the TCDID and CALLID formatted appropriately method svclog { tag message } # method recoverLogs {} # These methods are used for accessing and modifying the ModemState # object in the database method incrementSuccessiveFailures {} method getSuccessiveFailures {} method clearSuccessiveFailures {} method setModemMode {value expirationDay} method getModemMode {} # # UK AltEPG: new methods for improved daily call control # (Author: millsb, 2011-06-18) method useModem {} method deferCall {isUserInitiated} method setLastCallTime {} method sendTivoCallMessage {status text} method sendTivoMessage {subject body expiration} method parseCallWait {cwstring} method getTZOffset {time} method listAND {list1 list2} method buildHourList {hourspec} method changeNetcard {netcardCode ipAddress gateway netmask } method getAltEPGClientVersion {} # private variable _dsIrdb private variable _currentIrdbVersion "" # private variable _dsGenre private variable _currentGenreVersion "" # private variable _dsLogo private variable _currentLogoVersion "" # private variable _dsAffiliation private variable _currentAffiliationVersion "" # private variable _dsShowcase private variable _currentShowcaseVersion "" # private variable _premiumShowcases "" private variable _captureRequests "" private variable _menuItems "" private variable _otherDataSets "" # private variable GC_ONLY_NOW 0 private variable INDEX_ONLY_NOW 1 private variable GC_AND_INDEX_SOON 2 private variable srb private variable host private variable port private variable nDtvTuners 0 private variable rbBackgrounds "" } body TClient::setSvrRespRef {ref} { set srb $ref } body TClient::getRunningSwName {} { # # Open /etc/build-version, read the 2nd line # The second line should look like: # 2000.04.28-1528 2.0.D6 # Match on the second field and return it # set version "UNKNOWN" try { set fd [open /etc/build-version r] gets $fd line gets $fd line regexp ".+ (.+)" $line match version close $fd } catch errCode { putlog "Failure reading s/w version: $errCode" } return $version } body TClient::handleDataSet {} { if [catch {DataSet _dsIrdb $Inc::TS_IRDB_DATASET} res] { putlog "DataSets may not be enabled, could not find IrDbVersion: $res" } else { # puts "Setting _currentIrdbVersion to [_dsIrdb getVal ServerVersion]" set _currentIrdbVersion [_dsIrdb getVal ServerVersion] delete object _dsIrdb } # if [catch {DataSet _dsGenre $Inc::TS_GENRE_DATASET} res] { putlog "DataSets may not be enabled, could not find GenreVersion: $res" } else { set _currentGenreVersion [_dsGenre getVal ServerVersion] delete object _dsGenre } # if [catch {DataSet _dsLogo $Inc::TS_LOGO_DATASET} res] { putlog "DataSets may not be enabled, could not find LogoVersion: $res" } else { set _currentLogoVersion [_dsLogo getVal ServerVersion] delete object _dsLogo } # if [catch {DataSet _dsAffiliation $Inc::TS_AFFILIATION_DATASET} res] { putlog "DataSets may not be enabled, could not find AffiliationVersion: $res" } else { set _currentAffiliationVersion [_dsAffiliation getVal ServerVersion] delete object _dsAffiliation } # if [catch {DataSet _dsShowcase $Inc::TS_SHOWCASE_DATASET} res] { putlog "DataSets may not be enabled, could not find ShowcaseVersion: $res" } else { set _currentShowcaseVersion [_dsShowcase getVal ServerVersion] delete object _dsShowcase } handleVariableDataSets } body TClient::handleVariableDataSets {} { ForeachMfsFile id name type "/DataSet" "" { if {$name != $Inc::TS_GENRE_DATASET && $name != $Inc::TS_IRDB_DATASET && $name != $Inc::TS_AFFILIATION_DATASET && $name != $Inc::TS_LOGO_DATASET && $name != $Inc::TS_SHOWCASE_DATASET } { set dsType [string range $name 0 2] try { RetryTransaction { set dsObj [db $db openid $id] set dsVers [dbobj $dsObj get ServerVersion] } if { $dsType == $Inc::TS_PREMIUM_SHOWCASE_PREFIX } { append _premiumShowcases "$name-$dsVers|" } elseif { $dsType == $Inc::TS_CAPTURE_REQUEST_PREFIX } { append _captureRequests "$name-$dsVers|" } elseif { $dsType == $Inc::TS_MENU_ITEM_PREFIX } { append _menuItems "$name-$dsVers|" } else { append _otherDataSets "$name-$dsVers|" } } catch errorCode { putlog "Error reading dataset $name: $errorCode" } } } } body TClient::getTZ {} { # Default to Pacific set tz 4 set tvStandard "" if {[catch {set tvStandard $env(TV_STD)}]} { set tvStandard "NTSC" } if {$tvStandard == "PAL"} { # Use the UK timezone set tz 7 } try { RetryTransaction { # putlog "TClient-lib retry a" set setup [db $db open /Setup] set tz [dbobj $setup get TimeZone] if { $tz == "" } { set tz 4 } } } catch errCode { putlog "Error loading Setup: $errCode" } # translate from enum values to offsets from GMT. # In the future - the database value will BE the offset from GMT... switch -exact -- $tz { 1 {return 5} 2 {return 6} 3 {return 7} 4 {return 8} 5 {return 9} 6 {return 10} 7 {return 0} 8 {return 1} default {putlog "unknown timezone $tz"} } return 8 } body TClient::waitForTime {timestamp} { set whence [clock scan $timestamp -gmt 1] incr whence [expr 3600 * [getTZ]] set now [clock seconds] # handle the case where the requested time has already # passed in the current day, we wait for tomorrow # if {$now > $whence} { incr whence 86400 } puts "now : $now [clock format $now -format %D%t%r]" puts "whence : $whence [clock format $whence -format %D%t%r]" if {$now > $whence} { puts "This should never happen, ntpdate problem?" return 0 } set waiting [expr $whence - $now] # # this should never happen, but if it does # set the value to 24 hours's worth of seconds # if {$waiting > 86400} { set waiting 86400 } puts "Waiting $waiting seconds." #updateStatus "Pending restart" updateStatus $StatusStrings::PendingRestart after [expr $waiting * 1000] #updateStatus "Succeeded" updateStatus $StatusStrings::Succeeded puts "Timer has expired..." return 1 } body TClient::registerNewSoftware {} { set activated 1 set fireReboot "02:00" putlog "registerNewSoftware: getting SwSystemName" try { RetryTransaction { # putlog "TClient-lib retry b" # For backwards compatibility with old databases, default # to "master" of there is no explicit setting. set name master # Don't use the Setup itcl object here. Keep this script # lean and mean. # The ServiceInfo and SwSystemName fields are optional, and may not # be present. This will only change name from "master" to something # else if the field is present in the db set setup [db $db open /Setup] set info [dbobj $setup get ServiceInfo] set name [dbobj $info get SwSystemName] } } catch errCode { putlog "Error loading Setup: $errCode" } # Now we know the name of the SwSystem to run. Check to see if it # should be installed. It should be installed if it there *and* # it's not active yet. # # Note: we don't consider it a failure to not be able to # find the software system we're told to run (especially since # "none" is a possible name for a software system). # set install 0 try { RetryTransaction { set sw [db $db open /SwSystem/$name] set active [dbobj $sw get Active] if { $active != 1 } { putlog "Software system $name is present and NOT active" set install 1 } else { putlog "Software system $name is present and active" } } } catch errCode { putlog "Failure reading software system $name: $errCode" } if { ! $install } { return } # Check to see if there is *any* active software system. If # we're running in response to an emergency message from MyWorld # due to the lack of an active SwSystem, there's no point in waiting. set fActiveSoftware 1 try { RetryTransaction { # putlog "TClient-lib retry d" db $db open /SwSystem/ACTIVE } } catch errCode { putlog "Can't find active SwSystem: $errCode" set fActiveSoftware 0 } if { $fActiveSoftware } { set waitingToReboot 1 putlog "Software is not active, new software will be installed at $fireReboot" waitForTime $fireReboot } putlog "Rebooting to install new software..." after 5000 reboot } ######## # # LastDayForStation # ######## body TClient::lastDayForStation { stationId } { set lastDay 0 # # Start off with the lastDay as today, then start # looking for any holes (or when we run out of StationDays) # set today [expr [clock scan "12:00"] / 86400 ] set lastDay $today set badStationId 0 ForeachMfsFile id name type "/Schedule" "$stationId:" { set thisDay [lindex [split $name ":"] 1] # # There can be old days not yet deleted, skip them # if { $thisDay >= $today } { if { $thisDay == $lastDay } { incr lastDay 1 } else { putlog "Hole found in $stationId at $lastDay" set badStationId $stationId break; } } } if {$lastDay == $today || $badStationId != 0} { try { RetryTransaction { set badStationObj [db $db openid $stationId] set sId [dbobj $badStationObj get ServerId] set sCallSign [dbobj $badStationObj get CallSign] } if {$sId == ""} { # This is not a real station, skip it. return -1 } putlog "HOLE INFO: station=$sCallSign sId=$sId lastDay=$lastDay" } catch errCode { putlog "Error reading badStationObj: $stationId ($errCode)" } } incr lastDay -1 return $lastDay } ######## # # getHeadendIDList - Return | separated list of Headends with # appended version (i.e. day) needed # ######## body TClient::getHeadendIDList {} { set lastDay -1 set station 0 set retHeadStr "" set headendid "" putlog "getting headend ID List info" # # First get the list of Headend TMS ids, and station object ids. # try { set listOfHeadendsWithStations {} RetryTransaction { # putlog "TClient-lib retry f" # Open the setup object. It's always present by the time # we get around to doing a call. set setup [db $db open /Setup] # # For each of the SignalSource objects: # - get the TMS ID of the headend # - create a list of stationId's for that Source's Headend # foreach sigSrc [dbobj $setup get Source] { # Get the active headend object which may or may not be # there. It's set after the first setup call. set stationIdList {} set headend [dbobj $sigSrc get Headend] if { $headend == "" } { putlog "Signal source has no headend: ignoring" continue } putlog "working on headend: $headend" # Find the TMS name for the headend. if [catch {set headendid [dbobj $headend get TmsHeadendId]}] { # Setup has not been run or the headend object is missing. putlog "Didn't find TmsHeadendId" set headendid "" set sid 0 } else { putlog "Found TmsHeadendId = $headendid" set sid [dbobj $headend fsid] } # Don't bother looking for missing days if headend object missing if {$sid != 0} { # Here, we're computing the most recent day for a given channel in # our lineup. set channelList [dbobj $sigSrc get Channel] foreach channel $channelList { lappend stationIdList [dbobj $channel gettarget Station] } } # Make a list of headend, stationIdList set headendWithStations [list $headendid $stationIdList] # Add this list to the list of lists lappend listOfHeadendsWithStations $headendWithStations } } puts "listOfHeadendsWithStations = $listOfHeadendsWithStations" # # Now, for each headend, find the last day of program guide # data where ALL stations have data. # foreach headendWithStations $listOfHeadendsWithStations { set headend [lindex $headendWithStations 0] set stationIdList [lindex $headendWithStations 1] # the default is 0 set lastDay 0 foreach stationId $stationIdList { # $stationId at this point looks something like 3645/-4 set station [lindex [split $stationId /] 0] # remember, StationDays from the TiVo service # are still day-based (they are collections # of approx 24 hours worth of data which are 0 GMT # aligned) -- this is not necessarily the # case for APG-based boxes, where station # days can be much less than 24 hours or # much longer. set lastDayForStation [lastDayForStation $station] if {$lastDayForStation == -1} { continue } if { $lastDay == 0 } { set lastDay $lastDayForStation } if { $lastDayForStation < $lastDay } { set lastDay $lastDayForStation } putlog "Station $station last day is $lastDayForStation (lastDay=$lastDay)" } putlog "Last day of programming data for $headend is $lastDay" append retHeadStr "$headend-$lastDay|" putlog "retHeadStr = $retHeadStr" } } catch errCode { putlog "Error accessing setup: $errCode" } return $retHeadStr } ######## # # getCurMessages - get all the global system messages currently # in the DB. # ######## body TClient::getCurMessages {} { # # Have to check for non-duplicate messages in both places # set msgs "" set msgList {} ForeachMfsFile id name type "/MessageItem/MessageBoard" "" { try { RetryTransaction { set msgObj [db $db openid $id] set fromId [dbobj $msgObj get FromId] set servId [dbobj $msgObj get ServerId] if {$servId != ""} { putlog "found message $servId (localId = $id), from $fromId" if {$fromId == $Inc::MSG_SRC_SERVICE} { lappend msgList $id set vers [dbobj $msgObj get Version] append msgs "${servId}-${vers}|" } } } } catch errCode { putlog "Error ($errCode) reading /MessageItem/MessageBoard/$name" } } ForeachMfsFile id name type "/MessageItem/PreTivoCentral" "" { set addIt 1 foreach done $msgList { if {$done == $id} { set addIt 0 break } } if {$addIt} { try { RetryTransaction { set msgObj [db $db openid $id] set fromId [dbobj $msgObj get FromId] set servId [dbobj $msgObj get ServerId] if {$servId != ""} { putlog "found message $servId (localId = $id), from $fromId" if {$fromId == $Inc::MSG_SRC_SERVICE} { lappend msgList $id set vers [dbobj $msgObj get Version] append msgs "${servId}-${vers}|" } } } } catch errCode { putlog "Error ($errCode) reading /MessageItem/PreTivoCentral/$name" } } } putlog "returning messages: $msgs" return $msgs } ######## # # getWaitingCount - count the number of objects in /Database/Waiting, # and return that number -- this is used server-side to determine # if/what we need to send back to the client. # ######## body TClient::getWaitingCount {} { set count 0 ForeachMfsFile id name type "/Database" "Waiting" { incr count } return $count } ######## # # getCenterID - Rc.tivoinit should have set this environment variable. # ######## body TClient::getCenterID {} { global env return $env(SerialNumber) } ######## # # getLocationID - We append the version on to the value. # ######## body TClient::getLocationID {} { global env set wantDBS 0 set postalCode "" set postalCodePrefix "" set retPostalCode "" set found 0 set tvStandard "" if {[catch {set tvStandard $env(TV_STD)}]} { set tvStandard "NTSC" } # # If this is a first guided setup call we want to delete all # DBS objects to make certain we don't have two in the database # at one time. # if {$callReason == $Inc::TS_ID_SETUPHEAD} { putlog "Removing DBS objects in guided setup." ForeachMfsFile id name type "/PostalCode" "DBS" { # Remove this PostalCode object set pcStr "/PostalCode/$name" try { RetryTransaction { set dbsObj [db $db open $pcStr] dbobj $dbsObj markasrubbish } } catch errCode { putlog "Error trying to markasrubbish $pcStr: $errCode" } } } try { RetryTransaction { # Get the postal code from the setup object. This should have been set # by the box setup process. set setup [db $db open /Setup] set postalCode [dbobj $setup get PostalCode] set postalCodePrefix [string range $postalCode 0 1] putlog "Current postalcode: $postalCode" # grab the list of Signal Source objects and iterate through them set sigSrcList [dbobj $setup get Source] foreach sigSrc $sigSrcList { # Is this a DBS-type of source? set sigType [dbobj $sigSrc get SignalType] if {$sigType == 3} { set wantDBS 1 } } } } catch errCode { putlog "Error loading Setup: $errCode" } # get the local postalcode version if { $postalCode != "" } { set oid 0 set retPostalCode $postalCode # Look through the postal codes. ForeachMfsFile id name type "/PostalCode" $postalCode { set oid $id } if {$oid == 0} { # No data found for our postalcode, dummy it to download the first time. append retPostalCode "-0" } else { try { RetryTransaction { set obj [db $db openid $oid] # else get the version of the object and append it. append retPostalCode "-[dbobj $obj get ServerVersion]" } } catch errCode { putlog "Error ($errCode) reading /PostalCode/$name" } } } # get the satellite postalcode version, if necessary if {$wantDBS == 1} { # Get list of all DBS objects in database. set dbsPcList "" ForeachMfsFile id name type "/PostalCode" "DBS" { lappend dbsPcList $name } if { [llength $dbsPcList] > 0 && $tvStandard != "PAL"} { putlog "DBS PostalCode list: $dbsPcList" # First look for DBS~PostalCodePrefix. set dbsPostalCode "DBS~$postalCodePrefix" if { [lsearch -exact $dbsPcList $dbsPostalCode] != -1 } { set found 1 } else { # If I couldn't find DBS~PostalCodePrefix, look for DBS. set dbsPostalCode "DBS" if { [lsearch -exact $dbsPcList $dbsPostalCode] != -1 } { set found 1 } else { # If I couldn't find DBS~PostalCodePrefix or DBS, look for DBS~CANADA. set dbsPostalCode "DBS~CANADA" if { [lsearch -exact $dbsPcList $dbsPostalCode] != -1 } { set found 1 } } } if { $found } { putlog "Using satellite location ID: $dbsPostalCode" # get the server version of $dbsPostalCode try { RetryTransaction { set obj [db $db open "/PostalCode/$dbsPostalCode"] # get the version of the object and append it. set serverVersion [dbobj $obj get ServerVersion] append retPostalCode "|$dbsPostalCode-$serverVersion" } } catch errCode { # No data found for DBS, dummy it to download the first time. putlog "Error ($errCode) reading /PostalCode/$dbsPostalCode" append retPostalCode "|DBS~$postalCodePrefix-0" } # Go through and remove any DBS objects not currently being used. foreach pc $dbsPcList { if { $pc != $dbsPostalCode } { # Remove this PostalCode object set pcStr "/PostalCode/$pc" try { RetryTransaction { set dbsObj [db $db open $pcStr] dbobj $dbsObj markasrubbish putlog "Removing unneeded postalcode object: $pc" } } catch errCode { putlog "Error trying to markasrubbish $pcStr: $errCode" } } } } } elseif { [llength $dbsPcList] > 0 && $tvStandard == "PAL"} { set dbsPostalCode "DBS" if { [lsearch -exact $dbsPcList $dbsPostalCode] != -1 } { putlog "Using satellite location ID: $dbsPostalCode" # get the server version of $dbsPostalCode try { RetryTransaction { set obj [db $db open "/PostalCode/$dbsPostalCode"] # get the version of the object and append it. set serverVersion [dbobj $obj get ServerVersion] append retPostalCode "|$dbsPostalCode-$serverVersion" } set found 1 } catch errCode { # No data found for DBS, dummy it to download the first time. putlog "Error ($errCode) reading /PostalCode/$dbsPostalCode" } } } if { ! $found } { # No data found for DBS, dummy it to download the first time. if {$tvStandard != "PAL"} { putlog "Nothing found so returning: |DBS~$postalCodePrefix-0" append retPostalCode "|DBS~$postalCodePrefix-0" } else { putlog "Nothing found so returning: |DBS-0" append retPostalCode "|DBS-0" } } } # we return "PostalCode-HeadendPostalCodeVersion" eg. 94089-11 # if DBS is set on the box this would look like 94089-11|DBS-39 return $retPostalCode } ######## # # getCurrentShowcases # ######## body TClient::getCurrentShowcases {} { return "showcase0-0" } ######## # # setActiveSwName # ######## body TClient::setActiveSwName {name} { # # If the name is "local" then this is a developer # box (i.e. built via update-disk). Grab the default # version name to send back to HServer # if {$name == "local"} { set activeSwName $Inc::TS_DEFAULTSW_VERSION_IMPORTANT_KEEP_ME_UPDATED } else { set activeSwName $name # For all other names, confirm that the version # corresponds to the actual s/w we are running set ext2SwName [getRunningSwName] putlog "Found $ext2SwName running" if {[string first $ext2SwName $activeSwName] != 0} { putlog "ERROR: activeSw is $activeSwName, while $ext2SwName is running!!!!" svclog "software_mismatch" "DB_VER=$activeSwName EXT2_VER=$ext2SwName" } } } ######## # # getActiveSwName (used only in 411 calls, otherwise this function # is performed by getCurrentSoftware) # ######## body TClient::getActiveSwName {} { if {$activeSwName == ""} { set swName "UNKNOWN" try { RetryTransaction { set as [db $db open /SwSystem/ACTIVE] set swName [dbobj $as get Name] } } catch errMsg { putlog "Error getting ACTIVE s/w name: $errMsg" } setActiveSwName $swName } return $activeSwName } ######## # # getCurrentSoftware # ######## body TClient::getCurrentSoftware {} { set swList {} ForeachMfsFile id name type /SwSystem "" { # # If the name is "ACTIVE" then we will pick up those # objects via their other name, but do grab the name # of ACTIVE for backhaul reporting. # putlog "found name = $name" set sws [SwSystem sys#autosw1] try { if {$name == "ACTIVE"} { $sws loadNameFromDB $db $name setActiveSwName [$sws getSwName] } else { # # load up info from the SwSystem, but do not # let it give us local fs ids (developer builds) # # Yes, the RB list may be fetched/set more # than once, but that is an uncommon case (to # have more than ACTIVE loaded). # $sws disableLocalIds $sws loadFromDB $db $name append swList [$sws getIdStr] set rbBackgrounds [$sws getRbIdStr] } } catch errCode { putlog "Error ($errCode) reading /SwSystem/$name" } delete object $sws } return $swList } ######## # # getSvrInfo # # Reads from the tclient.conf file and finds an info line # labeled with the value in $code and returns it # ######## body TClient::getSvrInfo {code} { if {$code == "000" || $code == "911"} { # # These are the reserved codes which map to entries # in Addr.itcl. Don't read anything from the file # return "" } set confFile "$Inc::TC_TCLIENT_CONF" if [catch {open $confFile r} f] { putlog "couldn't open $confFile" return "" } else { while {[gets $f resLine] >= 0} { if { [regexp {^([0-9][0-9][0-9]):(.+)} $resLine match fileCode value] } { if {$fileCode == $code} { putlog "matched $code, returning value = $value" return $value } } } } putlog "no line matches code = $code" return "" } proc OnePosBoolean { negposboolean } { # whoa, undefined, leave it as such if { $negposboolean == "" } { return $negposboolean } if { $negposboolean } { return 0 } else { return 1 } } ######## # # login # ######## body TClient::login {} { global env set logStrm [log open TClient facdb priinfo] if {$waitingToReboot == 1} { puts "System is waiting to reboot" return 0 } cleanPools "login" log $logStrm "activated" # # Read the /Setup object # set setup [Setup setupObj#auto] $setup loadDb # # Get the 3 character code which defines what # out dial configuration is # set infoCode [$setup getVal dialConfig] putlog "dial config code: ($infoCode) found" set goodInfo 0 set svrInfo [getSvrInfo $infoCode] set phone "" set pppUser "" if {$svrInfo != ""} { # # If we found stuff in tclient.conf use any of # the fields we found (even pppUser & phone) # set svrInfoList [split $svrInfo ":"] if {[llength $svrInfoList] != 5} { putlog "bad Server Info entry: $svrInfo" } set phone [lindex $svrInfoList 0] set host [lindex $svrInfoList 1] set port [lindex $svrInfoList 2] set pppUser [lindex $svrInfoList 3] set pppPass [lindex $svrInfoList 4] set callDetailsSource "dialConfig $infoCode ($svrInfo)" set goodInfo 1 } if {$infoCode == "000" || $goodInfo == 0} { # # If reading the file failed or using 000 use the _DEF_ # parameters, but not for phone or pppUser. # putlog "Using default TiVo Service params" set host $Addr::TS_DEF_HOST set port $Addr::TS_DEF_PORT set pppPass $Addr::TS_DEF_PPPPASSWD set callDetailsSource "/tvlib/tcl/tv/Addr.itcl (default)" } elseif { $infoCode == "911"} { # # If the using 911, use the _EMG_ parameters # set host $Addr::TS_EMG_HOST set port $Addr::TS_EMG_PORT set phone $Addr::TS_EMG_PHONE set pppUser $Addr::TS_EMG_PPPUSER set pppPass $Addr::TS_EMG_PPPPASSWD set callDetailsSource "/tvlib/tcl/tv/Addr.itcl (emergency)" } #updateStatus "Preparing to call" setPhase $PhaseNames::SelectPhone # # If phone not defined by tclient.conf (normally it isn't) # go figure out the right one to use # if {$phone == ""} { set phone [findPhone $setup $callReason] } putlog "Host = $host" putlog "Port = $port" putlog "Phone = $phone" # # Might not find a number if not auth'd for toll free and: # - nothing set in curPhNum # - curPhNum is same as tollFreeNum # if {$phone == ""} { putlog "failed to find a phone number to use!" toggleLed 0 after 5000 #set subtype 8 #SendDialupEvent $subtype "Failed" #updateStatus "NH|Failed" updateStatus $StatusStrings::Failed sendTivoCallMessage "Failed" "Failed to find a phone number to use!" return 1 } setPhase $PhaseNames::PrepareCall # UK AltEPG: check for call deferred # (Author: millsb, 2011-06-18) # If this has been flagged as a deferred call, tidy up now and bail out. # (we treat a deferred call as a call failure, so the user can still see # when the last "real" call was made) # # callDeferred codes: # 0 - not deferred (continue with call) # 1 - deferred (don't call) # 2 - network settings changed (don't call) # if { $callDeferred != 0 } { putlog "Call deferred. Status => $StatusStrings::Failed, Phase => $PhaseNames::mCurrentPhaseRecord" toggleLed 0 after 5000 updateStatus $StatusStrings::Failed if { $callDeferred == 1 } { sendTivoCallMessage "Deferred" "Call deferred: $callDeferredReason" } return 1 } # Create an ID block. set idb [Ident idBlock#auto] set tcd411 [TCD411Rqst idBlock#auto] set callId [clock seconds] set lastCallIdFileName /var/persist/lastCallId if { [catch {set callIdFile [open $lastCallIdFileName w 0600]}]} { putlog "failed to open $lastCallIdFileName" } else { puts $callIdFile $callId close $callIdFile } # note: this information gets set for EVERY call, so put it here # to make sure it gets called.. # now set the customer-service-requested features: RetryTransaction { # putlog "TClient-lib retry l" set mysetup [db $db open /Setup] set mrtonePulseDial [dbobj $mysetup get DialMethod] if { $mrtonePulseDial == 0 } { set mrtonePulseDial "T" } else { set mrtonePulseDial "P" } $tcd411 setVal tonePulseDial $mrtonePulseDial $tcd411 setVal dialPrefix [lindex [dbobj $mysetup get DialPrefix] 0] $tcd411 setVal callWaitPrefix [lindex [dbobj $mysetup get CallWaitingPrefix] 0] set mroffHookDetect [dbobj $mysetup get DialHookCheck] set mroffHookDetect [OnePosBoolean $mroffHookDetect] set mrdialToneCheck [dbobj $mysetup get DialToneCheck] set mrdialToneCheck [OnePosBoolean $mrdialToneCheck] $tcd411 setVal offHookDetect $mroffHookDetect $tcd411 setVal dialToneCheck $mrdialToneCheck } if {$callReason == $Inc::TS_ID_ADMIN} { set tcdId 1 } else { set tcdId [getCenterID] } if {$pppUser == ""} { set pppUser "${tcdId}.${callId}@tivo.net" } if {$pppPass == ""} { set pppPass $Addr::TS_DEF_PPPPASSWD } if {$callReason != $Inc::TS_ID_411} { if [catch {handleDataSet} res] { puts "Could not get DataSet information: $res" } else { $idb setVal irdbVersion $_currentIrdbVersion $idb setVal genreVersion $_currentGenreVersion $idb setVal logoVersion $_currentLogoVersion $idb setVal showcaseVersion $_currentShowcaseVersion $idb setVal premiumShowcases $_premiumShowcases $idb setVal captureRequests $_captureRequests $idb setVal menuItems $_menuItems $idb setVal otherDataSets $_otherDataSets $idb setVal affiliationVersion $_currentAffiliationVersion } # not really sure where to put this guy! Let's put it # here though...if you can finda better place, pleasedo so. set identBlockConfigList {} set identBlockSignalList {} RetryTransaction { # putlog "TClient-lib retry m" set mySetup [db $db open /Setup] # Get a hold of the SignalSource object. set mySigSrcList [dbobj $mySetup get Source] # # For each of the Source objects: foreach mySigSrc $mySigSrcList { # now do the ident block stuff mentioned above... set mrsigtype [dbobj $mySigSrc get SignalType] set mrconnector [dbobj $mySigSrc get Connector] set mrremoteMethod [dbobj $mySigSrc get DBSRemoteMethod] set mrenterKey [dbobj $mySigSrc get EnterKeyRequired] # Booleans in the database are 0-positive. How silly set mrenterKey [OnePosBoolean $mrenterKey] set mrcableBoxCodeNum [dbobj $mySigSrc get CableBoxCodeNum] # Component is an optional object, and may return NULL set myComponent [dbobj $mySigSrc get Component] if { $myComponent != {} && $myComponent != "" } { set mrboxBrand [dbobj $myComponent get Name] } else { set mrboxBrand "" } set lineupList [dbobj $mySigSrc get LineupType] set mrlineups "" if {$lineupList == "" || $lineupList == {} } { set mrlineups "N" } else { foreach lineupItem $lineupList { if {$mrlineups == ""} { set mrlineups "$lineupItem" } else { append mrlineups "|$lineupItem" } } } set mrIrCodeSpeed [dbobj $mySigSrc get TunerDigitDelay] putlog "mrsigtype=$mrsigtype mrconnector=$mrconnector..." # great. now, set up pairs... # I hate TCL set hohoa [list $IdentPCodes::signalType $mrsigtype] set hohob [list $IdentPCodes::connector $mrconnector] set hohoc [list $IdentPCodes::dbsRemoteMethod $mrremoteMethod] set hohod [list $IdentPCodes::enterKeyRequired $mrenterKey] set hohoe [list $IdentPCodes::cableBoxCodeNum $mrcableBoxCodeNum] # Remove any curly-braces from the box brand, and replace # spaces with underscores to keep from screwing up BSM regsub -all {[\}\{]+} $mrboxBrand "" cleanedMrBoxBrand regsub -all {[ ]+} $cleanedMrBoxBrand "_" cleanedMrBoxBrand set hohof [list $IdentPCodes::cableBoxBrand $cleanedMrBoxBrand] set hohog [list $IdentPCodes::lineups $mrlineups] set hohoh [list $IdentPCodes::irCodeSpeed $mrIrCodeSpeed] set mistersublist [list $hohoa $hohob $hohoc $hohod $hohoe $hohof $hohog $hohoh] lappend identBlockSignalList $mistersublist } # now set up the config parameters set mrPostalCode [dbobj $mySetup get PostalCode] set mrDisableAutoRec [dbobj $mySetup get DisableAutoRec] # DB booleans are 0-positive...YUCK! set mrDisableAutoRec [OnePosBoolean $mrDisableAutoRec] set mrRecordQuality [dbobj $mySetup get RecordQuality] set mrTimeZone [dbobj $mySetup get TimeZone] set mrAudioSource [dbobj $mySetup get AudioSource] set mrNumTuners [dbobj $mySetup get TunerCount] set setupComplete [dbobj $mySetup get Complete] set hohoa [list $IdentPCodes::postalCode $mrPostalCode] set hohob [list $IdentPCodes::disableAutoRec $mrDisableAutoRec] set hohoc [list $IdentPCodes::recordQuality $mrRecordQuality] set hohod [list $IdentPCodes::timeZone $mrTimeZone] set hohoe [list $IdentPCodes::audioSource $mrAudioSource] set hohof [list $IdentPCodes::numTuners $mrNumTuners] set hohog [list $IdentPCodes::setupComplete $setupComplete] set mistersublist \ [list $hohoa $hohob $hohoc $hohod $hohoe $hohof $hohog] lappend identBlockConfigList $mistersublist } $idb setVal sourceParameterList $identBlockSignalList $idb setVal configParameterList $identBlockConfigList $idb setVal confInfo $svrInfo if {[catch {set dummy $env(DONT_USE_APG)}]} { set apgOnlyVar "" } else { set apgOnlyVar "false" } set tcdId [getCenterID] # combo boxes will all have 15 digit Id'sd if {[catch {set nDtvTuners $env(NUM_DTV_TUNERS)}]} { putlog "NUM_DTV_TUNERS not set!" # Fall back on known list... if { [string length $tcdId] == 15 } { if [regexp {(^[0-9][0-9][0-9])} $tcdId fullMatch tcdType] { if {$tcdType == "011" || $tcdType == "001" || $tcdType == "031"} { set nDtvTuners 2 } } } } if {$nDtvTuners > 0 && $apgOnlyVar == ""} { set useAPG "true" } $idb setVal apgOnly $apgOnlyVar $idb setVal reasonCode $callReason $idb setVal userInitiated $userInitiated $idb setVal centerID $tcdId # 2011-07-29 B.Mills Addition for AltEPG version control $idb setVal altEPGClientVersion [getAltEPGClientVersion] catch { $idb setVal nicInstalled $env(NIC_INSTALLED) } } if {$callReason == $Inc::TS_ID_TPING || $callReason == $Inc::TS_ID_ADMIN} { $idb setVal softwareDesc NONE $idb setVal locationID NONE $idb setVal headendID NONE $idb setVal sequenceCookie NONE $idb setVal showcaseDesc NONE $idb setVal swVerName [getActiveSwName] } elseif {$callReason == $Inc::TS_ID_411} { putlog "setting up TCD411 block" set areaCode [$setup getVal localAreaCode] $tcd411 setVal prefix [$setup getVal dialInPrefix] $tcd411 setVal dialInAreaCode [$setup getVal dialInAreaCode] $tcd411 setVal tollFreeAuth [$setup getVal tollFreeAuth] $tcd411 setVal areaCode $areaCode set curPhNum [getCurPhoneNum $setup] $tcd411 setVal curPhNum $curPhNum $tcd411 setVal objVer [getAreaCodeVer $areaCode] $tcd411 setVal tcdId $tcdId $tcd411 setVal callId $callId $tcd411 setVal callType TS_SR_TCD411 $tcd411 setVal swVerName [getActiveSwName] $tcd411 print # # 411 calls bypass the use of PartialDownload and so # we have to manually clean up the download directory # set f "" catch {set f [glob $Inc::TC_DOWNLOAD_DIR/*]} if {[llength $f]} { foreach i $f { file delete -force $i } } } else { if {$callReason == $Inc::TS_ID_TSTRING} { $idb setVal softwareDesc NONE $idb setVal showcaseDesc NONE $idb setVal locationID "94089-1" $idb setVal headendID "CA04614-1" } else { # Prior to all PGD calls, prepare the backhaul files. if {[catch {processLogs} oops]} { putlog "processLogs failed: $oops" } if {$callReason == $Inc::TS_ID_REGULAR} { # Prior to a "normal" call, cleanup old data. #updateStatus "Housekeeping..." setPhase $PhaseNames::Cleanup tidyUp } if {$callReason == $Inc::TS_ID_SETUP} { # we need to run the GC during the second guided # setup call to make sure there's space! setPhase $PhaseNames::Cleanup StartAndWaitForGc $GC_ONLY_NOW } setPhase $PhaseNames::Cleanup putlog "creating keyserver query" if {[catch {makeKeyQueryFile $Inc::TC_KEY_QUERY} err]} { putlog "Keyserver query error: $err" } putlog "setting up Ident Block" set messageDesc [getCurMessages] $idb setVal messageDesc $messageDesc putlog "getting current software" # # getCurrentSoftware also fetches: # - "Name" of ACTIVE # - list of replaceable backgrounds (rbBackgrounds) # $idb setVal softwareDesc [getCurrentSoftware] $idb setVal rbBackgrounds $rbBackgrounds $idb setVal swVerName [getActiveSwName] putlog "getting current showcases" $idb setVal showcaseDesc [getCurrentShowcases] putlog "getting locationID" $idb setVal locationID [getLocationID] putlog "getting headendID" if {$callReason != $Inc::TS_ID_SETUPHEAD} { # Don't generate last day info for APG-only if {$useAPG == "false"} { $idb setVal headendID [getHeadendIDList] } else { # This is a DITV combo box $idb setVal headendID "DITV-APG" } } else { putlog "skipping getHeadendIDList on SETUPHEAD call" $idb setVal headendID "" } # # Setup the 411 block for the calls that do 411 interactions # (Other than 411 call itself, that's up above) # if {$callReason == $Inc::TS_ID_SETUPHEAD || $callReason == $Inc::TS_ID_REGULAR} { putlog "setting up TCD411 block" set areaCode [$setup getVal localAreaCode] putlog "setting area code: $areaCode" $tcd411 setVal areaCode $areaCode $tcd411 setVal prefix [$setup getVal dialInPrefix] $tcd411 setVal dialInAreaCode [$setup getVal dialInAreaCode] $tcd411 setVal tollFreeAuth [$setup getVal tollFreeAuth] set curPhNum [getCurPhoneNum $setup] $tcd411 setVal curPhNum $curPhNum $tcd411 setVal objVer [getAreaCodeVer $areaCode] $tcd411 setVal tcdId $tcdId $tcd411 setVal callId $callId $tcd411 setVal callType TS_SR_ACCEPTED $tcd411 setVal swVerName [getActiveSwName] $tcd411 print } } $idb setVal sequenceCookie [$setup getVal sequenceCookie] } if {$callReason != $Inc::TS_ID_411} { # # Set inventoryFile and DialConfig in ident block from setup object # Set waiting count in ident block from proc. # $idb setVal inventoryFile [$setup getVal inventoryFile] $idb setVal dialConfig [$setup getVal dialConfig] $idb setVal waitingCount [getWaitingCount] $idb setVal demoMode [$setup getVal demoMode] $idb setVal dataGroupList [join [$setup getVal dataGroupList] "|"] set mrLastDate 0 set mrLastTime 0 set mrLastDirDate 0 set mrLastDirTime 0 set mrIdentBlockItem "0,0 0,0" try { RetryTransaction { set avalancheObj [db $db open /State/Avalanche] set mrLastDate [dbobj $avalancheObj get LastSuccessDownloadDate] set mrLastTime [dbobj $avalancheObj get LastSuccessDownloadTime] set mrLastDirDate [dbobj $avalancheObj get LastSuccessDirectoryDate] set mrLastDirTime [dbobj $avalancheObj get LastSuccessDirectoryTime] } } catch errCode { putlog "Error reading avalanche data object! ($errCode)" } if { [string length $mrLastDate] == 0 } { # Handles any possible clearout conditions (object there, but # attribute empty) set mrLastDate 0 set mrLastTime 0 } if { [string length $mrLastDirDate] == 0} { # Handles any possible clearout conditions (object there, but # attribute empty) set mrLastDirDate 0 set mrLastDirTime 0 } set mrIdentBlockItem "$mrLastDate,$mrLastTime $mrLastDirDate,$mrLastDirTime" $idb setVal lastAvalancheDownload $mrIdentBlockItem $idb print } delete object $setup set hserver_name "HServer" set tcd411_name "TCD411" putlog "Logging camid." if [catch { svclog "cam_id" "ID=$env(CAM_ID)" }] { putlog "CAM_ID not found." } putlog "Ird Id." if [catch { svclog "ird_id" "ID=$env(IrdSerialNumber)" }] { putlog "IrdSerialNumber not found." } if [useModem] { if {[connectPPP $phone $pppUser $pppPass] != 0} { delete object $idb delete object $tcd411 putlog "PPP has failed, we've warned the user, set status to Failed" toggleLed 0 after 5000 #set subtype 8 #SendDialupEvent $subtype "Failed" #updateStatus "NH|Failed" updateStatus $StatusStrings::Failed # Recover the logs and tell the EventLog to switch filenames # filenames back to their original naming convention recoverLogs # Failed without ever connecting. incrementSuccessiveFailures sendTivoCallMessage "Failed" "Failed to connect via modem:\n- $diallingError" return 1 } } else { # otherwise, we're in debug mode, so let's humor the VI and tell # it we dialed successfully #updateStatus "CL|Dialing..." setPhase $PhaseNames::Dial } # so we've successfully connected to PPP by now (or just via # ethernet if it's a debug box)...so enter the connecting phase. # Clear the TMK transaction-holdoff flag, so that UI transactions # don't cause us to back off repeatedly and tie up the phone holdoff 0 setPhase $PhaseNames::StartAuth log $logStrm "connect ${host}:${port}" putlog "About to connect to ${host}:${port}" set connOk 1 # # First off, POST any important info from the svclog postSvcLog # # Record the drive serial IDs in the moderated log # if [info exists env(HDA_ID)] { set hdaDriveid $env(HDA_ID) } else { set hdaDriveid "Unset" } if [info exists env(HDB_ID)] { set hdbDriveid $env(HDB_ID) } else { set hdbDriveid "Unset" } svclog "tcd_driveid" "HDA=$hdaDriveid HDB=$hdbDriveid" # # If this is a 411, REGULAR or SETUPHEAD, do the 411 interaction # set tcd411Resp [TCD411RespCli t411Block#auto] if {$callReason == $Inc::TS_ID_411 || $callReason == $Inc::TS_ID_SETUPHEAD || $callReason == $Inc::TS_ID_REGULAR} { putlog "about to do TCD411 Call" set connOk [doHttpCall $tcd411 $tcd411_name $host $port] putlog "doHttpCall returned: $connOk" if {$connOk } { set connOk [$tcd411Resp readBlock $tcd411_name] putlog "TCD411RespCli::readBlock returned: $connOk" if { $connOk } { # # Did the 411 exchange: show what we got and then # # $tcd411Resp print set setup [Setup setupObj#auto] $setup setVal dialInUpdateTime [expr [clock seconds] / 86400 ] $setup storeDb dialInUpdateTime delete object $setup } } } # # If this is not just a 411, do the normal HServer interaction # # set the host IP and port so file download stats can be posted $srb setHServerAddr $host $srb setHServerPort $port $srb setDebug 1 $srb setUseAPG $useAPG if { $connOk && $callReason != $Inc::TS_ID_411} { putlog "about to do HServer Call" $idb setVal callId $callId set connOk [doHttpCall $idb $hserver_name $host $port] putlog "doHttpCall returned: $connOk" if { $connOk } { set connOk [$srb readBlock $hserver_name] putlog "SvrResp::readBlock returned: $connOk" if { $connOk } { $srb print } } } if {! $connOk} { log $logStrm "failed connect - aborting" prierr delete object $idb delete object $tcd411 delete object $tcd411Resp putlog "Connect/POST has failed, we've warned the user, set status to Failed" putlog "failed connect - aborting" killproc pppd toggleLed 0 after 5000 #set subtype 8 #SendDialupEvent $subtype "Failed" #updateStatus "NH|Failed" updateStatus $StatusStrings::Failed # Recover the logs and tell the EventLog to switch filenames # filenames back to their original naming convention recoverLogs sendTivoCallMessage "Failed" "Connect/POST failed" return 1 } putlog "Connect/POST(s) succeeded" # # follow the convention of SvrResp::process where 0 is success # and 1 is failure # set ret 0 set updated411 0 if {$callReason == $Inc::TS_ID_411 || $callReason == $Inc::TS_ID_SETUPHEAD || $callReason == $Inc::TS_ID_REGULAR} { set ret [process411 $tcd411Resp $callReason] putlog "process411 returned: $ret" set updated411 [$tcd411Resp getUpdated] } set loc [$idb getVal locationID] set head [$idb getVal headendID] delete object $idb delete object $tcd411 unset tcd411 unset idb $srb setCallId $callId $srb setTcdId $tcdId if {$ret == 0} { # # For just a 411 call use SvrResp::loadSoftware # do the the dbloading, otherwise do the normal # "process" # if {$callReason == $Inc::TS_ID_411} { set ret [$srb loadSoftware $loc $head] $srb endConnection $ret } else { set ret [$srb process $loc $head] # # If a daily (REGULAR) call updated the area # code object, send an event to MyWorld so that # messages (PTCMs or MessageBoard) can be generated # if {$updated411 && $callReason == $Inc::TS_ID_REGULAR} { putlog "sending AreaCodes changed event" event send $TmkEvent::EVT_DATA_CHANGED $TmkDataChanged::AREACODES 0 } } } else { $srb endConnection $ret } toggleLed 0 set backHaulDone [$srb getBackHaulDone] putlog "backHaulDone is $backHaulDone" if { $backHaulDone == 0 } { recoverLogs } else { # Tell the EventLog to switch filenames back to their # original naming convention event send $TmkEvent::EVT_LOGMGR 1 0 } if { $callReason == $Inc::TS_ID_SETUP } { # we want to force and wait for indexing here... # PPS: what should this phase be???? setPhase $PhaseNames::IndexShows StartAndWaitForGc $INDEX_ONLY_NOW } elseif {$callReason == $Inc::TS_ID_REGULAR} { # on a regular daily call, we clean up non-authorized datasets CleanupDataSets } else { # the pgd-changed message will encourage the # gc to run "soon" & therefore index "soon". } unset loc unset head if {$commitNow == 1} { log $logStrm "attempting immediate software install" exec $env(TIVO_ROOT)/tvbin/tivosh $env(TIVO_ROOT)/tvbin/installSw.itcl } # Don't go into "pending reboot" for test or 411 calls if {$callReason != $Inc::TS_ID_411 && $callReason != $Inc::TS_ID_TPING} { # # Checking for new software installation # registerNewSoftware } # cleanup catch {file delete /var/tmp/pppaddr} log $logStrm "completed" if {$ret == 0} { updateStatus $StatusStrings::Succeeded sendTivoCallMessage "Succeeded" "Call succeeded" setLastCallTime } else { sendTivoCallMessage "Failed" "Call failed" updateStatus $StatusStrings::Failed } return $ret } body TClient::getCurPhoneNum { setup } { set numList [$setup getVal dialInPrefix] set retNum [lindex $numList 0] putlog "getCurPhoneNum : dialinprefix = '$retNum'" set numList [$setup getVal dialInAreaCode] append retNum [lindex $numList 0] putlog "getCurPhoneNum : +dialinareacode = '$retNum'" set numList [$setup getVal dialInNum] append retNum [lindex $numList 0] putlog "getCurPhoneNum : +dialinnum = '$retNum'" return $retNum } body TClient::findPhone { setup calltype } { if {$useDefaultNumber == 1 || $calltype == $Inc::TS_ID_411 || $calltype == $Inc::TS_ID_SETUPHEAD} { return [getTollFreeNum ""] } set tollFreeAuth [$setup getVal tollFreeAuth] set tollFreeNum [$setup getVal tollFreeNum] set curPhNum [getCurPhoneNum $setup] putlog "and now curphnum = '$curPhNum'" if {$tollFreeAuth == "" || $tollFreeAuth == {} } { set tollFreeAuth $TollFreeAuth::UPGRADE_AUTH putlog "storing initial value to tollFreeAuth: $tollFreeAuth" $setup setVal tollFreeAuth $tollFreeAuth $setup storeDb tollFreeAuth } putlog "curPhNum is ($curPhNum), tollFreeAuth is ($tollFreeAuth)" if {$curPhNum == ""} { if {$tollFreeAuth == $TollFreeAuth::UPGRADE_AUTH || $tollFreeAuth == $TollFreeAuth::AUTHORIZED || $tollFreeAuth == $TollFreeAuth::TEMP_AUTH} { putlog "allowing Def TFN use based on TFA" return [getTollFreeNum ""] } else { putlog "No Def TFN use with blank PhNum" return "" } } if {$curPhNum == $tollFreeNum} { if {$tollFreeAuth == $TollFreeAuth::UPGRADE_AUTH || $tollFreeAuth == $TollFreeAuth::AUTHORIZED || $tollFreeAuth == $TollFreeAuth::TEMP_AUTH} { putlog "allowing TFN use based on TFA" return [getTollFreeNum $curPhNum] } else { putlog "No TFN use based on TFA" return "" } } set callDetailsSource "$callDetailsSource + MFS/Setup/SvrInfo" putlog "returning regular PhNum: ($curPhNum)" return ${curPhNum} } body TClient::getTollFreeNum {curTollFreeNum} { if {$useBackupTollFree == 1} { set callDetailsSource "$callDetailsSource + Addr.itcl (backup)" return $Addr::TS_BACKUP_PHONE } elseif {$curTollFreeNum == "" || $curTollFreeNum == {} } { set callDetailsSource "$callDetailsSource + Addr.itcl (default)" return $Addr::TS_DEF_PHONE } set callDetailsSource "$callDetailsSource + MFS/Setup/SvrInfo" return $curTollFreeNum } body TClient::getAreaCodeVer {areaCode} { if {$areaCode == ""} { return "" } set servVersion 0 try { RetryTransaction { # putlog "TClient-lib retry n" set areaCodeObj [db $db open /AreaCode/$areaCode] set servVersion [dbobj $areaCodeObj get ServerVersion] } putlog "Found version $servVersion of AreaCode $areaCode" } catch errCode { putlog "Error reading area code object ($areaCode)! ($errCode)" putlog "Using $servVersion of AreaCode $areaCode" } return $servVersion } body TClient::doHttpCall { argObj name host port} { set sendFileName "/var/tmp/${name}.send" set recvFileName "/var/tmp/${name}.recv" catch {file delete $sendFileName} catch {file delete $recvFileName} set rc [$argObj writeBlock $name] if {$rc == 1} { set cmd "$Inc::TS_DEF_HPOST_PROG ${host}:${port} $sendFileName $recvFileName 300 ON" putlog "Executing HTTP command: $cmd" if [catch {eval exec $cmd >>$Inc::TC_HTTP_LOG} res] { putlog "http POST command failed: $res" set httpLogMessage "$httpLogMessage\nHTTP POST failed: error=$res; command=$cmd" set rc 0 } else { set httpLogMessage "$httpLogMessage\nHTTP POST OK; command=$cmd" } } return $rc } body TClient::process411 {tcd411Resp reason} { # # follow the convention of SvrResp::process where 0 is success # and 1 is failure # set errMsg [$tcd411Resp getVal errMsg] set tollFreeAuth [$tcd411Resp getVal tollFreeAuth] set areaCodeObj [$tcd411Resp getVal areaCodeObj] set newTollFreeNum [$tcd411Resp getVal tollFreeNum] set rc 0 if {$errMsg != ""} { putlog "Got error response from 411 service: $errMsg" if {$areaCodeObj != "NONE"} { # All errors cause call failure, except when it is # because the service says "NONE" for areaCodeObj. # In this case my world will detect this because # no object got loaded. set rc 1 } } if {$areaCodeObj == "OK"} { putlog "current AreaCode object is OK" } elseif {$areaCodeObj == "NONE"} { # There is no corresponding object! # My world will detect this (no object got loaded) # # Server is also setting errMsg in this case, so # we should never get here, but keep it for completeness. putlog "didn't find an AreaCode object!" } else { set cmdStr [CmdStr cms#auto] $cmdStr setCmd $areaCodeObj $cmdStr setTcdId $tcdId $cmdStr setCallId $callId $cmdStr setDebug 1 set cmdRet [$cmdStr process $Inc::TC_DOWNLOAD_DIR] delete object $cmdStr if {$cmdRet != 0} { putlog "Failed to download area code object: $cmdRet" set rc 1 } else { $srb new411Data } $tcd411Resp setUpdated 1 } set setNewTFA 0 set eventToSend 0 set setup [Setup setupObj#auto] $setup loadDb set thePhNum [getCurPhoneNum $setup] set curTollFreeNum [$setup getVal tollFreeNum] set curTollFreeAuth [$setup getVal tollFreeAuth] set updateList {} if {$tollFreeAuth != ""} { putlog "TFA is $tollFreeAuth" # # We never write the values 1 or 2 (UPGRADE_AUTH or # TEMP_AUTH) by means of server responses. We only # write 0 (NOT_AUTHORIZED) by means of recieving a 4. # All other states are handled below. # if {$tollFreeAuth == $TollFreeAuth::AUTHORIZED} { if {$curTollFreeAuth == $TollFreeAuth::TEMP_AUTH || $curTollFreeAuth == $TollFreeAuth::NOT_AUTHORIZED || $curTollFreeAuth == $TollFreeAuth::UPGRADE_AUTH} { # Authorizing from temp, not auth'd, or temp auth'd states. # Send "YES" event. set setNewTFA 1 set eventToSend $TmkDataChanged::YES_TOLLFREE } } elseif {$tollFreeAuth == $TollFreeAuth::REQUEST_DENIED} { if {$curTollFreeAuth == $TollFreeAuth::TEMP_AUTH || $curTollFreeAuth == $TollFreeAuth::UPGRADE_AUTH || $curTollFreeAuth == $TollFreeAuth::AUTHORIZED} { # De-authorizing from all auth'd states # Don't write the "4", write 0, no_auth instead. # If not in UPGRADE, send "NO" event so that MW can # do the one-time "request denied" message. set tollFreeAuth $TollFreeAuth::NOT_AUTHORIZED set setNewTFA 1 if {$curTollFreeAuth != $TollFreeAuth::UPGRADE_AUTH} { set eventToSend $TmkDataChanged::NO_TOLLFREE } } } elseif {$tollFreeAuth == $TollFreeAuth::UPGRADE_TIMEOUT && $reason != $Inc::TS_ID_SETUPHEAD} { if {$curTollFreeAuth == $TollFreeAuth::UPGRADE_AUTH} { # De-authorizing from the upgrade state only # This is used to allow someone to request temp auth # on the very day that we time out their upgrade auth # because "TIMEOUT" won't affect TEMP_AUTH above. set tollFreeAuth $TollFreeAuth::NOT_AUTHORIZED set setNewTFA 1 } } if {$setNewTFA} { putlog "Setting tollFreeAuth to $tollFreeAuth" $setup setVal tollFreeAuth $tollFreeAuth lappend updateList tollFreeAuth } else { putlog "Not overwriting $curTollFreeAuth with $tollFreeAuth" set tollFreeAuth $curTollFreeAuth } if {$tollFreeAuth == 0} { putlog "toll free auth is off" if {$thePhNum == "" || $thePhNum == $curTollFreeNum} { putlog "removing toll free num from DB" $setup setVal dialInNum "" $setup setVal dialInPrefix "" $setup setVal dialInAreaCode "" lappend updateList dialInNumbers } } } if {$newTollFreeNum != $curTollFreeNum} { putlog "Setting tollFreeNum to $newTollFreeNum" $setup setVal tollFreeNum $newTollFreeNum lappend updateList tollFreeNum if {$curTollFreeNum == $thePhNum} { # Store the new toll free number in the DB: # MW prefers this to be as one number in dialInNum putlog "changing old toll free num $thePhNum" $setup setVal dialInPrefix "" $setup setVal dialInAreaCode "" $setup setVal dialInNum $newTollFreeNum lappend updateList dialInNumbers } } # Now do all /Setup mods as one transaction if {[llength $updateList]} { $setup storeDb $updateList } # Now send any event to MW if {$eventToSend} { putlog "sending data changed event to MW: $eventToSend" event send $TmkEvent::EVT_DATA_CHANGED $eventToSend 0 } return $rc } ######## # # processLogs - Pre-process the logs for backhaul prior to connecting. # ####### body TClient::processLogs {} { set lm [LogMgr lmobj#auto] $lm processSysLogs $Inc::TC_LOG_FILE_LIST $lm processObjLogsStart $Inc::TC_OBJLOG_CLEARLIST \ $Inc::TC_OBJLOG_ENCLIST \ $Inc::TC_OBJLOG_KEYLIST delete object $lm cleanPools "processLogs" } ######## # # init - read command line and handle options. # ####### body TClient::init {argvlist} { # default putlog "TClient: TClient-lib version $version" set callReason $Inc::TS_ID_REGULAR set userInitiated 1 initializePhase foreach arg $argvlist { if {$arg == ""} { putlog "skipping null arg" } else { # putlog "TClient::init processing arg=$arg" switch -glob -- $arg { -s {set callReason $Inc::TS_ID_SETUP} -h {set callReason $Inc::TS_ID_SETUPHEAD} -c {set commitNow 1} -t {set callReason $Inc::TS_ID_TPING} -ts {set callReason $Inc::TS_ID_TSTRING} -k {set callReason $Inc::TS_ID_ADMIN} -l {set callReason $Inc::TS_ID_LOOP} -t411 {set callReason $Inc::TS_ID_411} -td {set callReason $Inc::TS_ID_TPING set useDefaultNumber 1} -auto {set userInitiated 0} -backup {set useBackupTollFree 1} default {putlog "unknown flag: ($arg)"} } } } # UK AltEPG: determine whether call should be deferred # (Author: millsb, 2011-06-18) try { set callDeferred [deferCall $userInitiated] } catch errCode { putlog "Error in deferCall: $errCode" } return 0 } ######## # # connectPPP # ####### body TClient::connectPPP {phoneNumber pppUser pppPass} { global tcl_library catch {file delete /var/tmp/pppaddr} # Defaults for the following 5 values, lest they not # be in the DB set toneOrPulse 0 set dialPrefix "" set callWaitingPrefix "" set phoneAvailableDetection 1 set dialToneDetection 0 try { RetryTransaction { # putlog "TClient-lib retry p" set setup [db $db open /Setup] if {[dbobj $setup get DialMethod] != ""} { set toneOrPulse [dbobj $setup get DialMethod]} if {[dbobj $setup get DialPrefix] != ""} { set dialPrefix [dbobj $setup get DialPrefix]} if {[dbobj $setup get CallWaitingPrefix] != ""} { set callWaitingPrefix [dbobj $setup get CallWaitingPrefix]} if {[dbobj $setup get DialHookCheck] != ""} { set phoneAvailableDetection [dbobj $setup get DialHookCheck]} if {[dbobj $setup get DialToneCheck] != ""} { set dialToneDetection [dbobj $setup get DialToneCheck]} } } catch errCode { putlog "Error loading Setup: $errCode" } putlog " toneOrPulse = $toneOrPulse" if {$toneOrPulse == 1} { set toneOrPulse P } else { set toneOrPulse T } putlog " dialPrefix = $dialPrefix" putlog " callWaitingPrefix == $callWaitingPrefix" putlog " realCallWaitingPrefix == $realCallWaitingPrefix" putlog " phoneNumber = $phoneNumber" putlog " phoneAvailableDetection = $phoneAvailableDetection" if {$phoneAvailableDetection == 0} { set phoneAvailableDetection 1 } else { set phoneAvailableDetection 0 } putlog " dialToneDetection = $dialToneDetection" if {$dialToneDetection == 0} { set dialToneDetection 1 } else { set dialToneDetection 0 } set modemMode [getModemMode] set useV34 0 if {$modemMode == $Inc::MODEM_MODE_V34 } { set useV34 1 } putlog "Starting dial.expect with:" putlog " toneOrPulse = $toneOrPulse" putlog " dialPrefix = $dialPrefix" putlog " callWaitingPrefix = $callWaitingPrefix" putlog " realCallWaitingPrefix == $realCallWaitingPrefix" putlog " phoneNumber = $phoneNumber" putlog " phoneAvailableDetection = $phoneAvailableDetection" putlog " dialToneDetection = $dialToneDetection" putlog " useV34 = $useV34" #updateStatus "CL|Dialing..." setPhase $PhaseNames::Dial toggleLed 1 set connectionPath "Modem (number=$dialPrefix$realCallWaitingPrefix$phoneNumber)" # set result [exec /bin/expect $tcl_library/tv/dial.expect $toneOrPulse $dialPrefix $callWaitingPrefix $phoneNumber $phoneAvailableDetection $dialToneDetection $pppUser $pppPass $useV34] set result [exec /bin/expect $tcl_library/tv/dial.expect $toneOrPulse $dialPrefix $realCallWaitingPrefix $phoneNumber $phoneAvailableDetection $dialToneDetection $pppUser $pppPass $useV34] putlog "Whole result is $result" set code "GARBLED" regexp "dialcode is:(.+)" $result match code # Put in field for modem mode (V90 or V34) set modemMode V90 # IMPORTANT! IMPORTANT! MUST CHANGE! This string is highly dependant on the Conexant smart modem # AT command set. A more invasive change would be for dial.expect to report the modem speed in its # output if {[regexp "AT.*\\+MS=V90" $result] == 0} { set modemMode V34 } # svclog "tclient_dialcode" "CODE=$code PHONE=$phoneNumber PREFIX=$dialPrefix CALL_WAIT_PREFIX=$callWaitingPrefix PHONE_AVAIL_DETECT=$phoneAvailableDetection DIAL_TONE_DETECT=$dialToneDetection TONE_OR_PULSE=$toneOrPulse MODEM_MODE=$modemMode" svclog "tclient_dialcode" "CODE=$code PHONE=$phoneNumber PREFIX=$dialPrefix CALL_WAIT_PREFIX=$realCallWaitingPrefix PHONE_AVAIL_DETECT=$phoneAvailableDetection DIAL_TONE_DETECT=$dialToneDetection TONE_OR_PULSE=$toneOrPulse MODEM_MODE=$modemMode" unset result if {$code != "OK"} { # at this point, we need to send the failure string... set PhaseNames::mOverrideStatusString $code set diallingError "dialling failed : $code" unset code return 1 } #updateStatus "Answered" setPhase $PhaseNames::Answered putlog "Starting pppd, code=$code" unset code if [catch {exec /sbin/pppd nodetach &} msg] { set diallingError "ERROR starting pppd: $msg" putlog $diallingError return 1 } # # Here we wait until the net connection is up via ppp # #updateStatus "Connecting..." setPhase $PhaseNames::StartPPP after 1000 set i 0 while {$i < 10} { if [file exists /var/tmp/pppaddr] { return 0 } incr i putlog "waiting for PPP - $i" after 3000 } set diallingError "Timed out waiting for PPP" putlog $diallingError return 1 } ######## # # toggleLed # ####### body TClient::toggleLed {on} { if {$on == 1} { set on 10 } else { set on 11 } event send $TmkEvent::EVT_DIALUPEVENT $on 0 } ######## # # Cleanup Mempools # # Simple script -- look for files named /var/tmp/TclEvent* -- the postfix # on the filename is the PID of the process who owns that mempool, so if # that process doesn't exist, then we can delete the file. # ######## body TClient::CleanupMempools { } { set procs [ glob /proc/* ] try { set tclEventList [ glob /var/tmp/TclEvent* ] foreach file $tclEventList { regexp "/var/tmp/TclEvent(\[0-9\]+)" $file name pid if { [lsearch $procs "/proc/$pid"] == -1 } { file delete $file } } } catch errorStr { putlog "error globing for TclEvent: $errorStr" } } ######## # # CleanupDiagFiles # - Clean up the files that were left behind by the diag process just to # make sure that they don't hog up disk space. # ####### body TClient::CleanupDiagFiles {} { set files {cbar1.trp.rec cbar2.trp.rec cbar3.trp.rec} foreach filename $files { ForeachMfsFile id name type "/" $filename { RetryTransaction { # putlog "TClient-lib retry q" mfs unlink "/$name" } } } } ######## # # CleanupDataSets # ####### body TClient::CleanupDataSets {} { set authorizedGroups [split [$srb getVal dataGroupList] ","] # Here we remove all the DataSets objects which meet the following: # - the ExpirationPolicy is set to DataGroupListControlled (1) # - they are not in the groups list HServer sent us ForeachMfsFile id name type "/DataSet" "" { RetryTransaction { set obj [db $db openid $id] set expirationPolicy [dbobj $obj get ExpirationPolicy] if {$expirationPolicy == $ExpirationPolicy::DATAGROUPLISTCONTROLLED} { if {[lsearch -exact $authorizedGroups $name] == -1} { putlog "CleanupDataSets: removing DataSet $name" dbobj $obj markasrubbish } } } } } ######## # # StartAndWaitForGc # ####### set StillWaitingForGc 1 proc GotStatusMsg { evtype subtype } { global EventData StillWaitingForGc env if { [info exists env(LITTLE_ENDIAN)] } { binary scan $EventData iiii soFar outOf idRequestor idSubrequestor } else { binary scan $EventData IIII soFar outOf idRequestor idSubrequestor } set MARK_ACTIVE 0 set MARK_REACTIVE 1 set SWEEP 2 set SUCCEEDED 3 set FAILED 4 if { $idRequestor == [pid] } { if { ($subtype == $SUCCEEDED) || ($subtype == $FAILED) } { putlog "GotStatusMsg: $subtype" set StillWaitingForGc 0 } } } body TClient::SendGcRequest { request } { global env # flags == 1 is to request dialup_change events set flags 1 if { [info exists env(LITTLE_ENDIAN)] } { set data [binary format iii $flags [pid] $request] } else { set data [binary format III $flags [pid] $request] } event send $TmkEvent::EVT_DBGC_REQUEST $request $data } body TClient::StartAndWaitForGc { request } { global tcl_library StillWaitingForGc putlog "enter StartAndWaitForGc $request" event connect event register $TmkEvent::EVT_DBGC_STATUS GotStatusMsg SendGcRequest $request set StillWaitingForGc 1 while { $StillWaitingForGc } { puts "still waiting!" vwait StillWaitingForGc } event register $TmkEvent::EVT_DBGC_STATUS {} event disconnect putlog "finish StartAndWaitForGc $request" } ######## # # tidyUp # ####### body TClient::tidyUp {} { global tcl_library cleanPools "start tidyUp" CleanupDiagFiles CleanupMempools putlog "end of tidyup" cleanPools "end tidyUp" } body TClient::makeKeyQueryFile {filename} { file delete $filename set serialnumber "Unknown!" catch {set serialnumber [exec /tvbin/crypto -gsn]} set query "SN $serialnumber" set version "Unknown!" catch {set version [exec /tvbin/crypto -gsv]} set query "$query\nVERSION $version" set pubkey "Nokey!" catch {set pubkey [exec /tvbin/crypto -x -gek]} set query "$query\nPUBLICKEY $pubkey" # # Vs lbh guvax gung vg gehfgf # gur xrl gung lbh fraq # gura urer whfg sbe lbh # V'ir n oevqtr gb iraq # # Ohezn Funir # RetryTransaction { # putlog "TClient-lib retry r" set setup [FindOrCreateObject $db Setup /Setup] set mykeys [dbobj $setup get EncryptionKeys] } set nkeys 0 foreach key $mykeys { regsub {,.*$} $key "" keyname if {$nkeys == 0} { set query "$query\nKEYRING $keyname" } else { set query "$query;$keyname" } incr nkeys } set headends 0 ForeachMfsFile id name type /Headend "" { if {$headends == 0} { set query "$query\nHEADEND $name" } else { set query "$query;$name" } incr headends } set headends 0 ForeachMfsFile id name type /HeadendTms "" { if {$headends == 0} { set query "$query\nHEADENDTMS $name" } else { set query "$query;$name" } incr headends } set outfile [open $filename w 0600] puts $outfile $query puts $outfile "END" close $outfile } ################################################# # # # Finite state machine and status string section # # ################################################# ############### # # SetStatusDB: sets the message from "msg" to the /Status/LastCallStatus # attribute # ############### proc SetStatusDB { db msg } { #puts "In setstatusdb, msg=$msg" try { RetryTransaction { putlog "writing $msg to LastCallStatus" set setup [db $db open /Setup] dbobj $setup set LastCallStatus $msg } } catch errCode { putlog "Error settting setup object! ($errCode)" return 0 } #puts "exiting setstatusdb, msg=$msg" return 1 } ######## # # InitializePhase # Sets the state to the initialized "nothing" state. # ######## body TClient::initializePhase {} { set PhaseNames::mOverrideStatusString "" set PhaseNames::mCurrentPhaseRecord $PhaseNames::Initialize SetStatusDB $db $StatusStrings::InProgress } ######### # # setPhase: call where there use to be a "updateStatus "Dialing..." # or something like that... # Sets the local state record, then sets the status db to "In Progress", # then calls update status with the "In Progress" message. This will cause # the yin-yang logo to update (if necessary) # ######### body TClient::setPhase { phase } { #puts "In setPhase, phase=$phase" set PhaseNames::mCurrentPhaseRecord $phase updateStatus $StatusStrings::InProgress #puts "exiting setPhase, phase=$phase" } ####### # # GetPhase # ###### body TClient::getPhase {} { return $PhaseNames::mCurrentPhaseRecord } ##### # # UpdateStatus: when msg is not one of the enumerated values, OR there is # no valid current state, then sendString is called directly # #### body TClient::updateStatus {msg} { set alsoSendMessage 0 # If we don't have a state record (just checking the length right now, # that's not the best metric, I'm sure), then just print out the message # via send string # #puts "mCurrentPhaseRecord = $PhaseNames::mCurrentPhaseRecord" putlog "updateStatus: $msg $PhaseNames::mCurrentPhaseRecord" # if we are in a bogus state, just send a normal message without # modifying the DB if { [llength $PhaseNames::mCurrentPhaseRecord] < 3 } { sendString $msg #puts "leaving updateStatus, msg=$msg" return 0 } # Now, glean the message for success, failure, In progress, and # "the end thing" (to be filled in). Unfortunately, we cannot use # the definitions in the ".h" file, as switch will not take variables # as tags (no surprise) # now, send the event to MyWorld via TMK messages set phaseCode [lindex $PhaseNames::mCurrentPhaseRecord 0] # currently, these phase codes are not changed by the code below, # but may be some time in the future if { $msg == $StatusStrings::Failed } { svclog "tclient_result" "STATUS=Failed" if { $PhaseNames::mOverrideStatusString != ""} { set statusString $PhaseNames::mOverrideStatusString set PhaseNames::mOverrideStatusString "" } else { set statusString [lindex $PhaseNames::mCurrentPhaseRecord 2] } set phaseCode1 $TLCCodes::JustPrintIt # Now, write the message to the weirdo output file for TCPHONEHOME # note: shname is to prevent code line wrapping. That's all. set shname $PhaseNames::TClientResultFile if {[catch { set resfile [open "$shname" w]}]} { putlog "Could not open result log file $shname" } else { set wholestring "$phaseCode$statusString" puts $resfile $wholestring puts "Saving '$wholestring' to result file" close $resfile } } elseif { $msg == $StatusStrings::Succeeded} { svclog "tclient_result" "STATUS=Succeeded" if { [llength $PhaseNames::mCurrentPhaseRecord] < 4 } { set statusString $StatusStrings::SucceededEnum } else { set statusString [lindex $PhaseNames::mCurrentPhaseRecord 3] } set phaseCode1 $TLCCodes::JustPrintIt } elseif { $msg == $StatusStrings::InProgress } { set statusString [lindex $PhaseNames::mCurrentPhaseRecord 1] set phaseCode1 $phaseCode } elseif { $msg == $StatusStrings::PendingRestart } { set statusString $StatusStringEnums::PendingRestart set phaseCode1 $TLCCodes::JustPrintIt } elseif { $msg == $StatusStrings::AwaitingReboot } { # note: using the same string as Pending Restart # ON PURPOSE...sounds much less geeky set statusString $StatusStringEnums::PendingRestart set phaseCode1 $TLCCodes::JustPrintIt } else { sendString $msg return 0 } # by now, we know that we have a valid StatusDB value in msg, so use # that for, well, the statusDB, if it has changed since the # last time. if { $msg != $lastStatusDBMsg} { SetStatusDB $db $msg set lastStatusDBMsg $msg } set totalMessageString $phaseCode1$statusString SendDialupEvent $DialupTMKSubtypes::Change $totalMessageString return 1 } body TClient::sendString {msg} { # send a dialup event with subtype (change), text "NH" (just # put up the message, change nothing else) # be sure to revert to the commented-out line SendDialupEvent $DialupTMKSubtypes::Change $msg #puts "Exiting sendString, msg=$msg" } body TClient::getBackHaulDone {} { return $backHaulDone } body TClient::svclog { tag message } { set fd [open $Inc::TC_SVC_LOG_FILE "a"] set now [clock seconds] puts $fd "$tag TCD_ID=$tcdId CALL_ID=$callId TIME=$now $message" close $fd } body TClient::postCommLog {} { if {! [file exists $Inc::TC_COMM_LOG_TEMP]} { putlog "no comm log file to post" return } if {! [file size $Inc::TC_COMM_LOG_TEMP]} { putlog "comm log file empty" return } set commLogScript "tivo-service/commlog.cgi" set postUrl "http://$host:$port/$commLogScript" if {! [postGenericFile $Inc::TC_COMM_LOG_TEMP $postUrl]} { # Don't just rename; some may have come in while we we're trying # make the call time catch {eval exec /bin/cat $Inc::TC_COMM_LOG_TEMP >> $Inc::TC_COMM_LOG_FILE} } catch {file delete $Inc::TC_COMM_LOG_TEMP} } body TClient::postSvcLog {} { if {[file exists $Inc::TC_SVC_LOG_FILE]} { # HTTP POST the svclog file to the same port as HServer set svcLogScript "tivo-service/mlog.cgi" set postUrl "http://$host:$port/$svcLogScript" postGenericFile $Inc::TC_SVC_LOG_FILE $postUrl } else { putlog "The service log: $Inc::TC_SVC_LOG_FILE does not exist!" } } body TClient::postGenericFile {file url} { set cmd "$Inc::TS_DEF_HPOST_BACKHAULPROG $file $url OFF OFF ON" putlog "Executing HTTP command: $cmd" set rc 0 if {[catch {eval exec $cmd} err]} { putlog "Failed while POSTing downloaded files stats: $err" set httpLogMessage "$httpLogMessage\nFile POST failed: error=$err, command=$cmd" } else { file delete -force $file set httpLogMessage "$httpLogMessage\nFile POST OK, command=$cmd" set rc 1 } return $rc } body TClient::recoverLogs {} { if {[file exists $Inc::TC_PRVLOG_FILE] && [file exists $Inc::TC_PRVLOG_FILE_DIVERT]} { # Restore the saved Remote Key clicks and append the # latest to the end of the current file catch {eval exec /bin/cat $Inc::TC_PRVLOG_FILE >> $Inc::TC_PRVLOG_FILE_DIVERT} # Tell the EventLog to switch filenames back to their # original naming convention event send $TmkEvent::EVT_LOGMGR 1 0 } } body TClient::getModemMode {} { set modemMode $Inc::MODEM_MODE_V90 set expirationDay 0 set today [lindex [DateNow] 0] try { RetryTransaction { set modem [FindOrCreateObject $db ModemState /State/Modem] set modemMode [dbobj $modem get CurrentMode] set expirationDay [dbobj $modem get ExpirationDay] } } catch errCode { putlog "getModemMode: Error getting ModemState: ($errCode), return V90" return $Inc::MODEM_MODE_V90 } if { $modemMode == "" } { set modemMode $Inc::MODEM_MODE_V90 } if { $expirationDay == "" } { set expirationDay 0 } # DOH! Either ModemMode was blank OR expirationDay is out of date # So, set the mode to V90. if {$modemMode != $Inc::MODEM_MODE_V90 && $expirationDay > 0 && $expirationDay < $today} { setModemMode $Inc::MODEM_MODE_V90 0 set modemMode $Inc::MODEM_MODE_V90 } # Otherwise, return what we found... return $modemMode } body TClient::setModemMode {value expirationDay} { try { RetryTransaction { set modem [FindOrCreateObject $db ModemState /State/Modem] dbobj $modem set CurrentMode $value dbobj $modem set ExpirationDay $expirationDay } } catch errCode { putlog "setModemMode: Error setting ModemState: ($errCode) to $value,$expirationDay" return 0 } return 1 } body TClient::getSuccessiveFailures {} { set numFails 0 try { RetryTransaction { set modem [FindOrCreateObject $db ModemState /State/Modem] set numFails [dbobj $modem get SuccessiveFailures] } } catch errCode { putlog "getSuccFail: Error getting ModemState: ($errCode), return 0" set numFails 0 } if { $numFails == "" } { set numFails 0 } return $numFails } # Clears the successive failure attribute of the ModemState, BUT DOES NOT # set mode back to V90: this is the responsibility of getModemMode ONLY body TClient::clearSuccessiveFailures {} { set oldFailures 0 try { RetryTransaction { set modem [FindOrCreateObject $db ModemState /State/Modem] set oldFailures [dbobj $modem get SuccessiveFailures] dbobj $modem set SuccessiveFailures 0 } } catch errCode { putlog "setSuccFail: Error setting ModemState: ($errCode), return 0" return 0 } svclog "tclient_modemstat" "CALL_FAILURES=0 PREVIOUS_FAILURES=$oldFailures" return 1 } body TClient::incrementSuccessiveFailures {} { set numFails 0 # Get Modem mode, perhaps resetting it to V90 set modemMode [getModemMode] try { RetryTransaction { set modem [FindOrCreateObject $db ModemState /State/Modem] set numFails [dbobj $modem get SuccessiveFailures] if {$numFails == ""} { set numFails 1 } else { set numFails [expr $numFails + 1] } # XXX REMOVE ME...this is just a hack to set it to V34 mode. # Actually, the actual code will go here...it just might not # look like this (although it will probably be close) # if {$numFails > 4 && $modemMode != $Inc::MODEM_MODE_V34} { # set today [lindex [DateNow] 0] # dbobj $modem set CurrentMode $Inc::MODEM_MODE_V34 # dbobj $modem set ExpirationDay [expr $today + 14] # putlog "NumFails ($numFails) > 16, setting to V34 mode" # } dbobj $modem set SuccessiveFailures $numFails } } catch errCode { putlog "incrementSuccFail: Error setting ModemState: ($errCode), return 0" set numFails 0 } # Don't report this number if we have no assurance on the value if {$numFails != 0 } { svclog "tclient_modemstat" "CALL_FAILURES=$numFails PREVIOUS_FAILURES=[expr $numFails - 1]" } return $numFails } # useModem : determines whether TiVo needs to establish PPP connection via the modem # return code: # 1 = use the modem # 0 = don't use the modem (ie a network connection is already available) # # useModem makes its decision as follows: # # If user has set dialPrefix to ",#4" via TiVo "Recorder & Phone Setup", DON'T use the modem # If user has set any other dialPrefix, DO use the modem # Otherwise (ie if dialPrefix is not set): # Look for file /var/tmp/net-eth: if present, DON'T use the modem # Look for file /var/tmp/net-ppp: if present, DON'T use the modem # Look for file /var/tmp/pppaddr: if absent, DON'T use the modem # Look for enviroment variable "DYNAMIC_NET_DEV": if present, DON'T use the modem # Otherwise, DO use the modem # # (Author: millsb, 2011/05/17) # Amendements: # 2011-06-11 Declare "env" as global (bug fix) # 2011-06-18 Added connectionPath diagnostics # body TClient::useModem {} { global env set dialPrefix "" try { RetryTransaction { set setup [db $db open /Setup] set dialPrefix [dbobj $setup get DialPrefix] } } catch errCode { putlog "useModem: Error loading DialPrefix: $errCode" } if { $dialPrefix == ",#4" } { putlog "useModem: dialPrefix=$dialPrefix - using existing network connection" set connectionPath "Network (dialPrefix=$dialPrefix)" return 0 } elseif { $dialPrefix != "" && $dialPrefix != "{}"} { putlog "useModem: dialPrefix=$dialPrefix - using dialup modem" set connectionPath "Modem " return 1 } else { putlog "useModem: dialPrefix not set, probing network..." if [ file exists /var/tmp/net-eth ] { putlog "useModem: network card found - IP address ip" set connectionPath "Network (/var/tmp/net-eth exists)" return 0 } elseif [ file exists /var/tmp/net-ppp ] { putlog "useModem: serial (PPP) network found - IP address ip" set connectionPath "Serial PPP (/var/tmp/net-ppp exists)" return 0 } elseif {! [ file exists /var/tmp/pppaddr ]} { putlog "useModem: /var/tmp/pppaddr not present - using existing network connection" set connectionPath "Network (/var/tmp/pppaddr absent)" return 0 } elseif { [info exists env(DYNAMIC_NET_DEV)] } { putlog "useModem: DYNAMIC_NET_DEV set to $env(DYNAMIC_NET_DEV) - using existing network connection" set connectionPath "Network (DYNAMIC_NET_DEV=$env(DYNAMIC_NET_DEV))" return 0 } else { putlog "useModem: no network found - using dialup modem" set connectionPath "Modem (no dial prefix)" return 1 } } } # deferCall: make decision on whether to defer call # # deferCall will defer automatic calls based on rules defined in the CallWaitingPrefix setting. # # CallWaitingPrefix rules are as follows: # # ,dd# Defer Call if the current day is one of 'dd' # ,dd,hhhh# Defer Call if the current day is one of 'dd' and the current time is in the range 'hhhh' # ,n* Defer call if the last successful call was less than 'n' days ago # ,0* Defer all automatic calls # ,dd,hhhh,dd# ) # ,dd,hhhh,dd,hhhh# ) You can string together multiple current day/time rules like this # ,dd,hhhh,dd,hhhh,dd# ) # # where: # dd : a list of day numbers (1=Mon,2=Tue,...,7=Sun) # hhhh : a range of hours (eg 0618 means 6am to 6pm) # # Examples: # ,67# means defer calls on Saturdays and Sundays, allow calls Mondays to Fridays # ,1234567# means defer calls on all days of the week (ie never allow automatic calls) # ,12345,0618# means defer calls during daytime (6am to 6pm) Mondays to Fridays, allow calls at all other times # ,12345,0618,6# means defer calls during daytime (6am to 6pm) Mondays to Fridays and defer calls all day Saturdays, allow calls at all other times # ,7* means defer calls if last call was less than 7 days ago # ,030* means defer calls if last call was less than 30 days ago # # Note that this is a non-standard use for the CallWaitingPrefix setting. Some users might need to use it for its # original purpose (ie to disable CallWaiting for the duration of the call). To achieve this the "real" call waiting # prefix should be added to the end. For example: # ,67#*43# means defer calls on Saturdays and Sundays, allow calls Mondays to Fridays and use the BT Star Services Call Waiting code (*43#). # # Test/Debugging features: # # 1. If file /var/tmp/tclient-debug exists, then pretend that all calls are automatic. This means you can test out this # code using the tivo remote, rather than having to wait for the next automatic daily call. # 2. If file /var/tmp/callWaitingPrefix exists, then read the call waiting prefix from that file rather than from the # database. Makes testing of various prefixes a lot easier. # # Network reconfiguation features: # # If callWaitPrefix is set to ,#n (n : 0 ... 9) then treat this code as a network reconfiguration request, and change # /etc/oztivo.conf to reflect the new configuration (reboot required to make it take effect). Don't do the call, but don't tell the # user it's deferred. # # (Author: millsb, 2011/07/19) body TClient::deferCall {isUserInitiated} { # Retrieve the call waiting prefix, and set class variable "realCallWaitPrefix" set callWaitPrefix "" set callDeferredReason "" try { RetryTransaction { set setup [db $db open /Setup] set callWaitPrefix [dbobj $setup get CallWaitingPrefix] } } catch errCode { putlog "deferCall: Error loading callWaitPrefix: $errCode" } # if in debug mode, pretend nothing is user initiated (for test purposes) if [ file exists /var/tmp/tclient-debug ] { putlog "deferCall: debug mode, so pretend auto-initiated" set isUserInitiated 0 } # read callWaitingPrefix from file if it exists (lazy override) if [ file exists /var/tmp/callWaitingPrefix ] { putlog "deferCall: reading callWaitingPrefix from file /var/tmp/callWaitingPrefix" set fd [open /var/tmp/callWaitingPrefix r] gets $fd callWaitPrefix close $fd } if { [regexp "^,\#(\[0-9])(,\[0-9*]+)?(,\[0-9*]+)?(,\[0-9*]+)?$" $callWaitPrefix all netcardCode ipAddress gateway netmask] } { putlog "deferCall: special callWait prefix set - changing netcard config (won't call)" putlog "calling changeNetcard with code=$netcardCode ip=$ipAddress gateway=$gateway netmask=$netmask" changeNetcard $netcardCode $ipAddress $gateway $netmask return 2 } putlog "deferCall: '$callWaitPrefix' didnt match '^,\#\[0-9]$'" try { parseCallWait $callWaitPrefix } catch errCode { putlog "Error in parseCallWait: $errCode" } # return false if this isn't a user-initiated call if { $isUserInitiated == 1 } { putlog "deferCall: not an automatic call, so OK, don't defer" return 0 } putlog "deferCall: checking whether to make call now. userinitiated = $isUserInitiated" set all "" set interval "" set today [clock seconds] set defer 0 # test for n* pattern (only call once every n days) putlog "deferCall: testing deferral rule '$deferralRule'" if { [regexp "^(\[0-9]+)\\*$" $deferralRule all interval] } { putlog "deferCall: matched interval rule, interval = $interval" if { $interval == 0 } { putlog "deferCall: callWaitPrefix = $callWaitPrefix - automatic calling is disabled" set callDeferredReason "Automatic calling is disabled (rule ,*$interval)" return 1 } putlog "deferCall: callWaitPrefix = $callWaitPrefix - dont call more frequently than $interval days" set lastCallTimeFileName /var/persist/lastCallTime set lastCallTime "" if { [catch {set callTimeFile [open $lastCallTimeFileName r]}]} { putlog "deferCall: failed to open $lastCallTimeFileName" } else { putlog "deferCall: found file $lastCallTimeFileName" gets $callTimeFile lastCallTime close $callTimeFile putlog "lastCallTime = $lastCallTime" } if { $lastCallTime == "" } { set lastCallTime 0 } set callDueTime [expr $lastCallTime + $interval * 86400 ] putlog "deferCall: callDueTime = $callDueTime" putlog "deferCall: date now = $today" if { $today <= $callDueTime } { putlog "deferCall: too soon to make call" set callDeferredReason "Too soon to call (rule ,*$interval)" set defer 1 } else { putlog "deferCall: it is not too soon to make the call" } } else { set calldays "" if { [regexp "^(\[0-9,]+)\\#$" $deferralRule all callhours] } { putlog "deferCall: matched callhours rule, callhours = $callhours" set fields [split $callhours ","] set allhours {1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1} set nohours {0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} set dayhours [list {} $allhours $allhours $allhours $allhours $allhours $allhours $allhours] set days "" foreach elt $fields { if { $days == "" } { set days $elt } else { putlog "deferCall: day(s) $days exclude hours $elt" set newhours [buildHourList $elt] set daynums [split $days ""] foreach day $daynums { set hours [listAND $newhours [lindex $dayhours $day]] set dayhours [lreplace $dayhours $day $day $hours] } set days "" } } if { $days != "" } { putlog "deferCall: day(s) $days exclude all hours" set daynums [split $days ""] foreach day $daynums { set dayhours [lreplace $dayhours $day $day $nohours] } } putlog "deferCall: permitted hours map:" for {set day 1} {$day <= 7} {incr day} { set hours [join [lindex $dayhours $day] "," ] putlog "deferCall: $day: $hours" } set tzoff [getTZOffset $today] set now [ expr { $today + $tzoff } ] set daytoday [clock format $now -format %u] # fudge because %H returns (eg) 08, which TCL thinks is invalid octal set hourtoday 1[clock format $now -format %H] set hourtoday [expr $hourtoday - 100] putlog "deferCall: daytoday = $daytoday" putlog "deferCall: hourtoday = $hourtoday" if { $daytoday == 0 } { # not certain this is necessary? set daytoday 7 putlog "deferCall: daytoday corrected = 7" } set allowed [lindex [lindex $dayhours $daytoday] $hourtoday] putlog "deferCall: allowed = $allowed" if { $allowed == 0 } { putlog "deferCall: daytoday $daytoday hour $hourtoday is not a permitted time for calling ($callhours)" set callDeferredReason "day $daytoday hour $hourtoday is not a permitted time for calling. Banned times: ($callhours)" set defer 1 } else { putlog "deferCall: daytoday $daytoday hour $hourtoday IS a permitted time for calling ($callhours)" } } } if { $defer == 0 } { putlog "deferCall: all checks complete - deferral not required" } return $defer } body TClient::listAND {list1 list2} { for {set index 0} {$index <= [llength $list1]} {incr index} { if {[lindex $list2 $index] == 0} { set list1 [lreplace $list1 $index $index 0] } } return $list1 } # hourspec format: # hhjj (4 digits): disallow hours hh-jj inclusive # any other spec is ignored (need to ensure hh and jj are in range 00-23) body TClient::buildHourList {hourspec} { set hlist [split $hourspec ""] set list {1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1} if { [llength $hlist ] == 4 } { set hfrom "" set hto "" set all "" regexp "(..)(..)" $hourspec all hfrom hto set hfrom 1$hfrom set hto 1$hto set hfrom [expr {$hfrom - 100}] set hto [expr {$hto - 100}] if {$hto == 0} { set hto 24} if { $hfrom <= 24 && $hto <= 24 } { for {set index $hfrom} {$index < $hto} {incr index} { set list [lreplace $list $index $index 0] } } } return $list } body TClient::setLastCallTime {} { set lastCallTimeFileName /var/persist/lastCallTime set today [clock seconds] if { [catch {set callTimeFile [open $lastCallTimeFileName w 0600]}]} { putlog "failed to open $lastCallTimeFileName" } else { putlog "found file $lastCallTimeFileName" puts $callTimeFile $today close $callTimeFile } } # send a tivo message to report on what happened in the call body TClient::sendTivoCallMessage {status text} { if { $diagnostics == 0 } { return 0 } putlog "Creating Dialup Message..." set now [clock seconds] set tzoff [getTZOffset $now] set localnow [ expr { $now + $tzoff } ] set localtimestamp [clock format $localnow -format "%a %d/%m/%y %T"] set userInitiatedText [expr (($userInitiated == 0)?"Automatic":"User Initiated")] set callReasonText [expr {($callReason == $Inc::TS_ID_REGULAR) ? "Regular" : ($callReason == $Inc::TS_ID_ADMIN) ? "Admin" : ($callReason == $Inc::TS_ID_SETUP) ? "Setup" : ($callReason == $Inc::TS_ID_TPING) ? "Test" : ($callReason == $Inc::TS_ID_TSTRING) ? "TString" : ($callReason == $Inc::TS_ID_SETUPHEAD) ? "SetupHead" : ($callReason == $Inc::TS_ID_LOOP) ? "Loop" : ($callReason == $Inc::TS_ID_411) ? "411" : "Unknown"}] set msgBody "$text,\nCall type : $userInitiatedText $callReasonText,\nConnection path : $connectionPath\nServer address : $host:$port\nLocal time : $localtimestamp\nCall details obtained from: $callDetailsSource\n$httpLogMessage" sendTivoMessage "Daily Call $status" $msgBody 7 } body TClient::sendTivoMessage {subject body expiration} { set dest 1 set msgPriority 2 set now [clock seconds] set tzoff [getTZOffset $now] set localnow [ expr { $now + $tzoff } ] set msgDate [expr $localnow / 86400] set msgTime [expr $localnow % 86400] set msgExpire [expr ($now / 86400) + $expiration ] try { set db [dbopen] RetryTransaction { set obj [db $db create MessageItem] dbobj $obj set DateGenerated $msgDate dbobj $obj set TimeGenerated $msgTime dbobj $obj set ExpirationDate $msgExpire dbobj $obj set From "TiVo TClient" dbobj $obj set Subject $subject dbobj $obj set Body $body dbobj $obj set FromId $Inc::MSG_SRC_INDIV dbobj $obj set Priority $msgPriority dbobj $obj remove Destination dbobj $obj add Destination $dest } # send an event to MyWorld for the new Message putlog "Calling event send $TmkEvent::EVT_DATA_CHANGED DATA_MESSAGES 0" event send $TmkEvent::EVT_DATA_CHANGED $TmkDataChanged::MESSAGES 0 dbclose $db } catch errCode { putlog "Error in sendTivoMessage: $errCode" } } # CallWaitingPrefix is repurposed to contain 3 elements, as follows: # # [deferralrule] [diagnosticrule] [realcallwaitingprefix] # # Each element is optional. # # deferralrule ::= "," n+ "*" || "," [0-9,]+ "#" (eg ,14* ,7* ,0* ,12345# ,67# ,12345,0618#) # diagnosticrule ::= n "#" (eg 0# 1# 9#) # realcallwaitingprefix ::= anything not beginning with "," # # parseCallWait parses the original callwaitingprefix and splits it into the above elements. # dererralrule is set to n* or n# (ie leading comma is removed) # diagnostics is set to 1 if not present, otherwise the trailing # is removed # realcallwaitingprefix is set to "" if not present body TClient::parseCallWait {cwstring} { set diagnostics 1 set deferralRule "" set realCallWaitingPrefix $cwstring set all "" set tmp "" set tmp2 "" regexp "^(,(\[0-9,]+\\#))?((\[0-9])\#)?(\[^,].*)?$" $cwstring all tmp deferralRule tmp2 diagnostics realCallWaitingPrefix if {$all == "" } { regexp "^(,(\[0-9]+\\*))?((\[0-9])\#)?(\[^,].*)?$" $cwstring all tmp deferralRule tmp2 diagnostics realCallWaitingPrefix } if { $diagnostics == "" } { set diagnostics 1 } putlog "ParseCallWait: diagnostics = '$diagnostics', deferralRule = '$deferralRule', cwprefix = '$realCallWaitingPrefix'" } set ::dstOfsList {} foreach {m w h} {4 0 1 11 0 1} { set doy [expr ([clock scan "$h:00 $m/1/1970" -gmt 1]/86400)+7*($w-1)] lappend ::dstOfsList [list $doy [expr $doy*86400 + $h*3600]] } # Determine the timezone offset for the specified time. # This is a UK-specific function - it returns the daylight savings offset (ie 3600 seconds in summer, 0 seconds in winter), # based on the standard rules (ie BST runs from 2am on last Sunday in March to 2am on last Sunday in October) # The logic is derived from the TiVoWebPlus module tz/GB.itcl body TClient::getTZOffset {time} { if {$time<=0} {return 0} set idx 0 set y [expr $time / 31536000] set leaps [expr ($y+2)>>2] set toy [expr ($time % 31536000) - $leaps*86400] for {set i 0} {$i<2} {incr i} { foreach {ddoy t} [lindex $::dstOfsList $idx] break if {$toy < $t+86400*((73-($ddoy+$y+$leaps))%7)} break incr idx } #puts "$idx,$ddoy,$toy,$i=[clock format $time]" return [expr ($i&1)*3600] } body TClient::changeNetcard {netcardCode ipAddress gateway netmask } { set setNicScript /hack/bin/setNic.bash set nic "" switch -exact -- $netcardCode { "0" {set nic Auto} "1" {set nic Modem} "2" {set nic PPPonDSS} "3" {set nic TurboNet} "4" {set nic Cachecard} "5" {set nic TiVoNet} "6" {set nic AirNet} default {set nic ""} } putlog "changeNetcard: changing to '$nic' (code=$netcardCode)" set error "" set gwvalue "" set ipvalue "" set maskvalue "" if { $ipAddress == ",0" } { set ipvalue "DHCP" } elseif { $ipAddress != "" } { if { [regexp "^,(\[0-9]+\\*\[0-9]+\\*\[0-9]+\\*\[0-9]+)$" $ipAddress dummy ipvalue ] } { regsub -all "\\*" $ipvalue "." ipvalue } else { set error "Illegal IP address: $ipAddress" } } if { $gateway != "" } { if { [regexp "^,(\[0-9]+\\*\[0-9]+\\*\[0-9]+\\*\[0-9]+)$" $gateway dummy gwvalue ] } { regsub -all "\\*" $gwvalue "." gwvalue } else { set error "Illegal Gateway: $gateway" } } if { $netmask != "" } { if { [regexp "^,(\[0-9]+)$" $netmask dummy maskvalue ] } { if { $maskvalue <= 32 } { set masks { "0.0.0.0" "128.0.0.0" "192.0.0.0" "224.0.0.0" "240.0.0.0" "248.0.0.0" "252.0.0.0" "254.0.0.0" "255.0.0.0" "255.128.0.0" "255.192.0.0" "255.224.0.0" "255.240.0.0" "255.248.0.0" "255.252.0.0" "255.254.0.0" "255.255.0.0" "255.255.128.0" "255.255.192.0" "255.255.224.0" "255.255.240.0" "255.255.248.0" "255.255.252.0" "255.255.254.0" "255.255.255.0" "255.255.255.128" "255.255.255.192" "255.255.255.224" "255.255.255.240" "255.255.255.248" "255.255.255.252" "255.255.255.254" "255.255.255.255" } set maskvalue [lindex $masks $maskvalue] } else { set error "Illegal Netmask: $netmask - cant be more than 32" } } else { set error "Illegal Netmask: $netmask - must be number in range 0..24" } } if { $error != "" } { putlog "changeNetCard: Error: $error" sendTivoMessage "Network Configuration Change Error" "Error specifying config change: $error" 7 } elseif { $nic != "" } { set result "error executing $setNicScript" catch {set result [exec /bin/bash $setNicScript $nic $ipvalue $gwvalue $maskvalue]} putlog "changeNetCard:$result" sendTivoMessage "Network Configuration Change" "TiVo network configuration altered. New setting = $nic" 7 } } body TClient::getAltEPGClientVersion {} { set altEPGClientVersionDefault "1.0b" set altEPGClientVersion "" set altEPGVersionFileName "/etc/altepg.version" try { set altEPGVersionFile [open $altEPGVersionFileName r] gets $altEPGVersionFile altEPGClientVersion close $altEPGVersionFile } catch errCode { putlog "Error $errCode opening $altEPGVersionFileName" } if { $altEPGClientVersion == "" } { putlog "altEPGClientVersion not set, using default ($altEPGClientVersionDefault)" } return $altEPGClientVersion } #* AltEPG Version Control #* #* Version 0.8 2011-08-19 millsb Development version #*