Index: libs/libmythtv/videosource.h
===================================================================
--- libs/libmythtv/videosource.h	(revision 14205)
+++ libs/libmythtv/videosource.h	(working copy)
@@ -62,7 +62,7 @@
 {
     Q_OBJECT
   public:
-    DataDirect_config(const VideoSource& _parent, int _source = DD_ZAP2IT); 
+    DataDirect_config(const VideoSource& _parent, int _ddsource); 
 
     virtual void load(void);
 
Index: libs/libmythtv/datadirect.h
===================================================================
--- libs/libmythtv/datadirect.h	(revision 14205)
+++ libs/libmythtv/datadirect.h	(working copy)
@@ -11,8 +11,9 @@
 
 enum DD_PROVIDERS
 {
-    DD_ZAP2IT = 0,
-    DD_PROVIDER_COUNT,
+    DD_ZAP2IT           = 0,
+    DD_SCHEDULES_DIRECT = 1,
+    DD_PROVIDER_COUNT   = 2,
 };
 
 class DataDirectURLs
Index: libs/libmythtv/datadirect.cpp
===================================================================
--- libs/libmythtv/datadirect.cpp	(revision 14205)
+++ libs/libmythtv/datadirect.cpp	(working copy)
@@ -542,7 +542,14 @@
         "http://datadirect.webservices.zap2it.com/tvlistings/xtvdService",
         "http://labs.zap2it.com",
         "/ztvws/ztvws_login/1,1059,TMS01-1,00.html");
+    DataDirectURLs urls1(
+        "Schedules Direct",
+        "http://webservices.schedulesdirect.tmsdatadirect.com"
+        "/schedulesdirect/tvlistings/xtvdService",
+        "http://schedulesdirect.org",
+        "/login/index.php");
     providers.push_back(urls0);
+    providers.push_back(urls1);
 
     QString tmpDir = "/tmp";
     tmpPostFile   = makeTempFile(tmpDir + "/mythtv_post_XXXXXX");
@@ -1018,7 +1025,7 @@
         "  channelMinor char(3) )";
 
     dd_tables["dd_schedule"] =
-        "( programid char(12),           stationid char(12), "
+        "( programid char(40),           stationid char(12), "
         "  scheduletime datetime,        duration time,      "
         "  isrepeat bool,                stereo bool,        "
         "  subtitled bool,               hdtv bool,          "
@@ -1028,7 +1035,7 @@
         "INDEX progidx (programid) )";
 
     dd_tables["dd_program"] =
-        "( programid char(12) NOT NULL,  seriesid char(12),     "
+        "( programid char(40) NOT NULL,  seriesid char(12),     "
         "  title varchar(120),           subtitle varchar(150), "
         "  description text,             mpaarating char(5),    "
         "  starrating char(5),           runtime time,          "
@@ -1050,19 +1057,19 @@
         "  partnumber int,               parttotal int,               "
         "  seriesid char(12),            originalairdate date,        "
         "  showtype varchar(30),         colorcode varchar(20),       "
-        "  syndicatedepisodenumber varchar(20), programid char(12),   "
+        "  syndicatedepisodenumber varchar(20), programid char(40),   "
         "  tvrating char(5),             mpaarating char(5),          "
         "INDEX progidx (programid))";
 
     dd_tables["dd_productioncrew"] =
-        "( programid char(12),           role char(30),    "
+        "( programid char(40),           role char(30),    "
         "  givenname char(20),           surname char(20), "
         "  fullname char(41), "
         "INDEX progidx (programid), "
         "INDEX nameidx (fullname))";
 
     dd_tables["dd_genre"] =
-        "( programid char(12) NOT NULL,  class char(30), "
+        "( programid char(40) NOT NULL,  class char(30), "
         "  relevance char(1), "
         "INDEX progidx (programid))";
 
Index: libs/libmythtv/videosource.cpp
===================================================================
--- libs/libmythtv/videosource.cpp	(revision 14205)
+++ libs/libmythtv/videosource.cpp	(working copy)
@@ -19,6 +19,7 @@
 #include <qmap.h>
 #include <qdir.h>
 #include <qprocess.h>
+#include <qdatetime.h>
 
 // MythTV headers
 #include "mythconfig.h"
@@ -42,6 +43,14 @@
 #include "videodev_myth.h"
 #endif
 
+static bool is_grabber_external(const QString &grabber)
+{
+    return !(grabber == "datadirect" ||
+             grabber == "eitonly" ||
+             grabber == "schedulesdirect1" ||
+             grabber == "/bin/true");
+}
+
 class RecorderOptions: public ConfigurationWizard
 {
   public:
@@ -148,7 +157,9 @@
 class DataDirectPassword: public LineEditSetting, public VSSetting {
   public:
     DataDirectPassword(const VideoSource& parent):
-        VSSetting(parent, "password") {
+        VSSetting(parent, "password")
+    {
+        SetPasswordEcho(true);
         setLabel(QObject::tr("Password"));
     };
 };
@@ -159,7 +170,6 @@
 {
     (void) uid;
     (void) pwd;
-    (void) _source;
 #ifdef USING_BACKEND
     if (uid.isEmpty() || pwd.isEmpty())
         return;
@@ -200,8 +210,11 @@
 void DataDirect_config::load() 
 {
     VerticalConfigurationGroup::load();
-    if ((userid->getValue() != lastloadeduserid) || 
-        (password->getValue() != lastloadedpassword)) 
+    bool is_sd_userid = userid->getValue().contains("@") > 0;
+    bool match = ((is_sd_userid  && (source == DD_SCHEDULES_DIRECT)) ||
+                  (!is_sd_userid && (source == DD_ZAP2IT)));
+    if (((userid->getValue() != lastloadeduserid) ||
+         (password->getValue() != lastloadedpassword)) && match)
     {
         lineupselector->fillSelections(userid->getValue(), 
                                        password->getValue(),
@@ -296,8 +309,7 @@
         "instead of just 'mythfilldatabase'.\nYour grabber does not provide "
         "channel numbers, so you have to set them manually.");
 
-    if (grabber != "datadirect" && grabber != "eitonly" && 
-        grabber != "/bin/true")
+    if (is_grabber_external(grabber))
     {
         VERBOSE(VB_IMPORTANT, "\n" << err_msg);
         MythPopupBox::showOkPopup(
@@ -365,9 +377,17 @@
     // only save settings for the selected grabber
     setSaveAll(false);
 
-    addTarget("datadirect", new DataDirect_config(parent));
-    grabber->addSelection("North America (DataDirect) (Internal)", "datadirect");
+    addTarget("schedulesdirect1",
+              new DataDirect_config(parent, DD_SCHEDULES_DIRECT));
+    grabber->addSelection("North America (SchedulesDirect.org) "
+                          "(Internal)", "schedulesdirect1");
 
+#if 1
+    addTarget("datadirect", new DataDirect_config(parent, DD_ZAP2IT));
+    grabber->addSelection(
+        "North America (TMS Labs) (Internal)", "datadirect");
+#endif
+
     addTarget("eitonly", new EITOnly_config(parent));
     grabber->addSelection("Transmitted guide only (EIT)", "eitonly");
 
Index: libs/libmyth/settings.cpp
===================================================================
--- libs/libmyth/settings.cpp	(revision 14205)
+++ libs/libmyth/settings.cpp	(working copy)
@@ -494,7 +494,8 @@
         connect(edit, SIGNAL(changeHelpText(QString)), cg, 
                 SIGNAL(changeHelpText(QString)));
 
-    edit->setRW(rw);
+    setRW(rw);
+    SetPasswordEcho(password_echo);
 
     return widget;
 }
@@ -519,6 +520,13 @@
     }
 }
 
+void LineEditSetting::SetPasswordEcho(bool b)
+{
+    password_echo = b;
+    if (edit)
+        edit->setEchoMode(b ? QLineEdit::Password : QLineEdit::Normal);
+}
+
 QWidget* SliderSetting::configWidget(ConfigurationGroup *cg, QWidget* parent,
                                      const char* widgetName) {
     QHBox* widget;
Index: libs/libmyth/mythcontext.h
===================================================================
--- libs/libmyth/mythcontext.h	(revision 14205)
+++ libs/libmyth/mythcontext.h	(working copy)
@@ -224,7 +224,7 @@
 
 /// Update this whenever the plug-in API changes.
 /// Including changes in the libmythtv class methods used by plug-ins.
-#define MYTH_BINARY_VERSION "0.20.20060828-4"
+#define MYTH_BINARY_VERSION "0.20.20070816-2"
 
 /** \brief Increment this whenever the MythTV network protocol changes.
  *
Index: libs/libmyth/settings.h
===================================================================
--- libs/libmyth/settings.h	(revision 14205)
+++ libs/libmyth/settings.h	(working copy)
@@ -276,7 +276,8 @@
 
 class LineEditSetting: virtual public Setting {
 protected:
-    LineEditSetting(bool readwrite = true) : edit(NULL) { rw = readwrite; };
+    LineEditSetting(bool readwrite = true) :
+        edit(NULL), rw(readwrite),  password_echo(false) { }
 public:
     virtual QWidget* configWidget(ConfigurationGroup *cg, QWidget* parent, 
                                   const char* widgetName = 0);
@@ -292,10 +293,12 @@
 
     virtual void setEnabled(bool b);
     virtual void setVisible(bool b);
+    virtual void SetPasswordEcho(bool b);
 
 private:
     MythLineEdit* edit;
     bool rw;
+    bool password_echo;
 };
 
 // TODO: set things up so that setting the value as a string emits
Index: programs/mythfilldatabase/filldata.cpp
===================================================================
--- programs/mythfilldatabase/filldata.cpp	(revision 14205)
+++ programs/mythfilldatabase/filldata.cpp	(working copy)
@@ -834,6 +834,24 @@
     return insert_channels;
 }
 
+bool is_grabber_external(const QString &grabber)
+{
+    return !(grabber == "datadirect" ||
+             grabber == "eitonly" ||
+             grabber == "schedulesdirect1" ||
+             grabber == "/bin/true");
+}
+
+bool is_grabber_datadirect(const QString &grabber)
+{
+    return (grabber == "datadirect") || (grabber == "schedulesdirect1");
+}
+
+bool is_grabber_labs(const QString &grabber)
+{
+    return grabber == "datadirect";
+}
+
 // DataDirect stuff
 void DataDirectStationUpdate(Source source, bool update_icons = true)
 {
@@ -852,7 +870,8 @@
         UpdateSourceIcons(source.id);
 
     // Unselect channels not in users lineup for DVB, HDTV
-    if (!insert_channels && (new_channels > 0))
+    if (!insert_channels && (new_channels > 0) &&
+        is_grabber_labs(source.xmltvgrabber))
     {
         bool ok0 = (logged_in == source.userid);
         bool ok1 = (raw_lineup == source.id);
@@ -877,6 +896,13 @@
 
 bool DataDirectUpdateChannels(Source source)
 {
+    if (!is_grabber_labs(source.xmltvgrabber))
+    {
+        VERBOSE(VB_IMPORTANT, "FillData: We only support "
+                "DataDirectUpdateChannels with TMS Labs channel editor");
+        return false;
+    }
+
     ddprocessor.SetListingsProvider(DD_ZAP2IT);
     ddprocessor.SetUserID(source.userid);
     ddprocessor.SetPassword(source.password);
@@ -2531,6 +2557,8 @@
 
     if (xmltv_grabber == "datadirect")
         return grabDDData(source, offset, *qCurrentDate, DD_ZAP2IT);
+    else if (xmltv_grabber == "schedulesdirect1")
+        return grabDDData(source, offset, *qCurrentDate, DD_SCHEDULES_DIRECT);
     else if (xmltv_grabber == "technovera")
     {
         VERBOSE(VB_ALL, "This grabber is no longer supported");
@@ -2857,7 +2885,7 @@
                                   .arg((*it).xmltvgrabber));
 
         QString xmltv_grabber = (*it).xmltvgrabber;
-        need_post_grab_proc |= (xmltv_grabber != "datadirect");
+        need_post_grab_proc |= !is_grabber_datadirect(xmltv_grabber);
 
         if (xmltv_grabber == "tv_grab_uk" || xmltv_grabber == "tv_grab_uk_rt" ||
             xmltv_grabber == "tv_grab_fi" || xmltv_grabber == "tv_grab_es" ||
@@ -2872,7 +2900,7 @@
             if (!grabData(*it, 0))
                 ++failures;
         }
-        else if ((xmltv_grabber == "datadirect") && dd_grab_all)
+        else if (is_grabber_labs(xmltv_grabber) && dd_grab_all)
         {
             if (only_update_channels)
                 DataDirectUpdateChannels(*it);
@@ -2882,7 +2910,7 @@
                 grabData(*it, 0, &qCurrentDate);
             }
         }
-        else if (xmltv_grabber == "datadirect" ||
+        else if (is_grabber_datadirect(xmltv_grabber) ||
                  xmltv_grabber == "tv_grab_se_swedb" ||
                  xmltv_grabber == "tv_grab_no" ||
                  xmltv_grabber == "tv_grab_de_tvtoday" ||
@@ -2906,7 +2934,7 @@
             // often decided by the person maintaining the grabbers.
             if (maxDays > 0) // passed with --max-days
                 grabdays = maxDays;
-            else if (xmltv_grabber == "datadirect")
+            else if (is_grabber_datadirect(xmltv_grabber))
                 grabdays = 14;
             else if (xmltv_grabber == "tv_grab_se_swedb")
                 grabdays = 10;
@@ -2922,7 +2950,7 @@
             if (grabdays == 1)
                 refresh_today = true;
 
-            if ((xmltv_grabber == "datadirect") && only_update_channels)
+            if (is_grabber_labs(xmltv_grabber) && only_update_channels)
             {
                 DataDirectUpdateChannels(*it);
                 grabdays = 0;
@@ -3860,8 +3888,9 @@
                        newsource.lineupid = sourcequery.value(5).toString();
 
                        sourcelist.append(newsource);
-                       if (newsource.xmltvgrabber == "datadirect")
-                           usingDataDirect = true;
+                       usingDataDirect =
+                           is_grabber_datadirect(newsource.xmltvgrabber);
+                           
                   }
              }
              else
