Index: libs/libmythtv/videosource.h
===================================================================
--- libs/libmythtv/videosource.h	(revision 14205)
+++ libs/libmythtv/videosource.h	(working copy)
@@ -110,7 +110,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)
@@ -13,8 +13,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");
@@ -1083,7 +1090,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,          "
@@ -1093,7 +1100,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,          "
@@ -1115,19 +1122,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)
@@ -20,6 +20,7 @@
 #include <qmap.h>
 #include <qdir.h>
 #include <qprocess.h>
+#include <qdatetime.h>
 
 // MythTV headers
 #include "mythconfig.h"
@@ -44,6 +45,14 @@
 #include "videodev_myth.h"
 #endif
 
+static bool is_grabber_external(const QString &grabber)
+{
+    return !(grabber == "datadirect" ||
+             grabber == "eitonly" ||
+             grabber == "schedulesdirect1" ||
+             grabber == "/bin/true");
+}
+
 VideoSourceSelector::VideoSourceSelector(uint           _initial_sourceid,
                                          const QString &_card_types,
                                          bool           _must_have_mplexid) :
@@ -295,8 +304,10 @@
 {
   public:
     DataDirectPassword(const VideoSource &parent) :
-        LineEditSetting(this), VideoSourceDBStorage(this, parent, "password")
+        LineEditSetting(this, true),
+        VideoSourceDBStorage(this, parent, "password")
     {
+        SetPasswordEcho(true);
         setLabel(QObject::tr("Password"));
     }
 };
@@ -307,7 +318,6 @@
 {
     (void) uid;
     (void) pwd;
-    (void) _source;
 #ifdef USING_BACKEND
     if (uid.isEmpty() || pwd.isEmpty())
         return;
@@ -348,8 +358,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(),
@@ -442,8 +455,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(
@@ -508,9 +520,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)
@@ -639,7 +639,8 @@
         connect(edit, SIGNAL(changeHelpText(QString)), cg, 
                 SIGNAL(changeHelpText(QString)));
 
-    edit->setRW(rw);
+    setRW(rw);
+    SetPasswordEcho(password_echo);
 
     return widget;
 }
@@ -664,6 +665,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)
@@ -208,7 +208,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.20070717-1"
+#define MYTH_BINARY_VERSION "0.20.20070816-1"
 
 /** \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)
@@ -200,7 +200,7 @@
 {
   protected:
     LineEditSetting(Storage *_storage, bool readwrite = true) :
-        Setting(_storage), edit(NULL), rw(readwrite) { }
+        Setting(_storage), edit(NULL), rw(readwrite), password_echo(false) { }
 
   public:
     virtual QWidget* configWidget(ConfigurationGroup *cg, QWidget* parent, 
@@ -217,10 +217,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)
@@ -26,6 +26,24 @@
 // filldata headers
 #include "filldata.h"
 
+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 FillData::DataDirectStationUpdate(Source source, bool update_icons)
 {
@@ -44,7 +62,8 @@
         icon_data.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);
@@ -69,6 +88,13 @@
 
 bool FillData::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);
@@ -251,6 +277,8 @@
 
     if (xmltv_grabber == "datadirect")
         return grabDDData(source, offset, *qCurrentDate, DD_ZAP2IT);
+    if (xmltv_grabber == "schedulesdirect1")
+        return grabDDData(source, offset, *qCurrentDate, DD_SCHEDULES_DIRECT);
 
     char tempfilename[] = "/tmp/mythXXXXXX";
     if (mkstemp(tempfilename) == -1)
@@ -486,7 +514,7 @@
 
         bool hasprefmethod = false;
 
-        if (xmltv_grabber != "datadirect")
+        if (is_grabber_external(xmltv_grabber))
         {
 
             QProcess grabber_capabilities_proc(xmltv_grabber);
@@ -584,9 +612,9 @@
             }
         }
 
-        need_post_grab_proc |= (xmltv_grabber != "datadirect");
+        need_post_grab_proc |= !is_grabber_datadirect(xmltv_grabber);
 
-        if ((xmltv_grabber == "datadirect") && dd_grab_all)
+        if (is_grabber_labs(xmltv_grabber) && dd_grab_all)
         {
             if (only_update_channels)
                 DataDirectUpdateChannels(*it);
@@ -601,7 +629,8 @@
             if (!grabData(*it, 0))
                 ++failures;
         }
-        else if ((*it).xmltvgrabber_baseline || xmltv_grabber == "datadirect")
+        else if ((*it).xmltvgrabber_baseline ||
+                 is_grabber_datadirect(xmltv_grabber))
         {
 
             QDate qCurrentDate = QDate::currentDate();
@@ -612,7 +641,7 @@
 
             if (maxDays > 0) // passed with --max-days
                 grabdays = maxDays;
-            else if (xmltv_grabber == "datadirect")
+            else if (is_grabber_datadirect(xmltv_grabber))
                 grabdays = 14;
 
             grabdays = (only_update_channels) ? 1 : grabdays;
@@ -620,7 +649,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;
Index: programs/mythfilldatabase/main.cpp
===================================================================
--- programs/mythfilldatabase/main.cpp	(revision 14205)
+++ programs/mythfilldatabase/main.cpp	(working copy)
@@ -579,8 +579,9 @@
                        newsource.xmltvgrabber_prefmethod = "";
 
                        sourcelist.append(newsource);
-                       if (newsource.xmltvgrabber == "datadirect")
-                           usingDataDirect = true;
+                       usingDataDirect =
+                           ((newsource.xmltvgrabber == "datadirect") ||
+                            (newsource.xmltvgrabber == "schedulesdirect1"));
                   }
              }
              else
