Saturday, March 21, 2009 - Posts

Saturday, March 21, 2009
via @fractalnavel: in the last twenty-four hours:
  • 2009.03.21 05:11: oh yeah - happy equinox http://www.die.net/earth/
  • 2009.03.21 05:13: man, that happened way too quick; only 270 more days to winter soltice !
  • 2009.03.22 00:50: https://www.mturk.com/mturk/conditionsofuse "3.b.(i) you will not use robots, scripts or other automated methods to complete the Services;"
  • 2009.03.22 00:51: why not ? who cares ? if i can create an automated process to satisfy the requirements, so much the better...
  • 2009.03.22 00:52: what about _any_ aids ? silly.
(pulled direct from twitter via custom job)
Posted by fractalnavel at 11:30 PM | with no comments

what you _don't_ see is what you get: digging into the details of .net reflector's forced auto-update "feature".

one little annoyance - and suspicion - in the .net development world is the behavior of .net reflector when it comes to updating itself.  there's no way around it.  and if you're not careful, the thing will even delete itself in some circumstances.  that behavior is suspiciously close to being a solid example of stallman's "treacherous computing" criticism.

phone home

using the current version, go to  "Help -> Check for Updates".  fiddler shows that Reflector connects to location http://reflector.red-gate.com/reflector.version, sending the request:

GET /Reflector.version HTTP/1.1
Cache-Control: no-cache, no-store, max-age=0<
Host: reflector.red-gate.com
Proxy-Connection: Keep-Alive

and getting the response:

HTTP/1.1 200 OK
Content-Length: 63
Content-Type: text/plain
Last-Modified: Fri, 17 Oct 2008 09:34:07 GMT
Accept-Ranges: bytes
ETag: "a4fb7b803b30c91:5fd"
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Date: Fri, 20 Mar 2009 20:08:16 GMT

5.1.4.0
4.0.0.0
http://downloads.red-gate.com/reflector.zip

setting up a fiddler auto-response for the request like this seems to work.  better would be to set up a dns entry somewhere rerouting that specific url to a (local) http proxy that does the same.  could even do this so that reflector versions across an organization or project pull from the same update cache - under the control of the consumer.

ok, so that satisfies a bit of paranoia regarding what the call-home exchange may have been.  why isn't it documented more transparently ? and still, that's not really acceptable behavior, for any reason.

delete me

 

next, need to install & run an old version to see what attempting to fire that up does.  i've got one hanging around from a couple of years ago, dated 2006.12.10, v4.2.51.0.

trying to fire it up results in:

reflector01

select "no", and i get this:

reflector02

reflector.exe was marked read only, so it remained.

running it again and responding "yes" to the update question, it reaches for http://www.aisto.com/roeder/dotnet/Reflector.version.  if it can't find that for some reason (say, from being offline), it displays an error message:

reflector03

and proceeds to (attempt to) delete the executable as before.

running again, responding "yes", and letting it find the (faked) response as above, it reaches for the download reference in the response.  failing here, it also attempts to delete the executable.

now, before going further, if i change the first number version in the response to be the same as the one i'm trying to run, the update dialog is still presented, and returns immediately with

reflector04

but - after closing this dialog, the deletion attempt is still made.  yeah, it's time-bombed from the inside alright.  i even tried feeding it the old version zip as the download reference in the faked response - that just loops the deletion / update process; good if you're in the mood for some strange sort of self-abuse.

the only way around that deletion that anyone seems to have found is to change the system date before starting the app.  i haven't tried, but it is probably possible to set up a cmd file to do the date change in a way reflector will recognize, launch & change back.

since reflector's internals are well protected, it seems the most practical approach is to hope redgate listens to the folks on its forums about this.

just ugly.

Posted by fractalnavel at 10:17 PM | with no comments
Filed under: ,
first refactoring of my twitter to blog post aggregator (code).

it usually takes me three rounds of coding to get something somewhat satisfactory - the original "just get it to work" phase, and two refactorings.  the first refactoring follows, with some notes in the comments for the next round:

  • fractalnavel.CS.PostTwitter.cs
    using System;
    using System.Xml;
    
    using CommunityServer.Blogs.Components;
    
    using CookComputing.XmlRpc;
    
    using fractalnavel.CS.components;
    
    namespace fractalnavel.CS
    {
    
        // TODO: 
        //  - log processing status; 
        //  - loop through multiple service/settings nodes (optionally post all together?)
        class CMain
        {
            [STAThread]
            static void Main(string[] args)
            {
                XmlDocument xmlSettings = new XmlDocument();
                xmlSettings.Load( args[0] ); 
                GetAndPost gap = new GetAndPost( 
                    xmlSettings.DocumentElement, 
                    (XmlRpcProxyGen.Create<IMetaWebLogNewPost>()).newPost 
                    );
    
                if ( gap.Get() ) 
                    gap.Post();
                else if ( gap.PostNone )
                    gap.Post( "nothin'" );
            }
        }
    
        [XmlRpcUrl("*** wherever it was put *** /metablog.ashx")] 
        public interface IMetaWebLogNewPost
        {
            [XmlRpcMethod("metaWeblog.newPost")]
            string newPost(
                string blogid,
                string username,
                string password,
                MetaWeblog.Post post,
                bool publish
                );
        }
        
    }
  • fractalnavel.CS.components.cs
    using System;
    using System.Xml;
    using System.Xml.Serialization;
    
    using CommunityServer.Blogs.Components;
    
    using fractalnavel.components;
    
    namespace fractalnavel.CS.components
    {
    
        // get xml, transform to post, post to blog.    
        public class GetAndPost
        {
            private MakeNewPost _doPost;
            private Settings _settings;
            private XmlDocument _xmldocAll = new XmlDocument();
            private string _strPostBody = string.Empty;
    
            public delegate string MakeNewPost(
                string blogid,
                string username,
                string password,
                MetaWeblog.Post post,
                bool publish
                );
    
            public GetAndPost( XmlNode nodSettings )
            {
                GetAndPost( nodSettings, (new MetaWeblog()).newPost );
            }
    
            public GetAndPost( XmlNode nodSettings, MakeNewPost DoPost )
            {
                _doPost = DoPost;
                _settings = (Settings) XmlUtils.Deserialize <Settings> ( nodSettings );
            }
            
            public bool PostNone {
                get{ return _settings.bPostNone; }
            }
    
            public string PostBody
            {
                set {_strPostBody = value;}
                
                // TODO: add xsl parameter handling (will pass various settings)
                get 
                {
                    if ( _strPostBody == string.Empty )
                        _strPostBody = XmlUtils.Transform( _xmldocAll, _settings.hrefXsl );
                    return _strPostBody;
                } 
            }
    
            /* 
            returns true if results contain status nodes
            ***twitter specific at the moment.***
            TODO: 
                - factor the href & success into a separate service interface, 
                - implement for each service, 
                - specify implementation class/assembly in config element, 
                - instantiate here, 
                - pass settings to service interface, 
                - and consume.
             */
            public bool Get() 
            {
                // Tue%2C+27+Mar+2007+22%3A55%3A48+GMT
                string href = _settings.hrefGet + "?count=200&since=" + ((DateTime.UtcNow).AddHours( - _settings.hours )).ToString("r");
                _xmldocAll.LoadXml( XmlUtils.GetTextFromHref( href, _settings.useridGet, _settings.pwdGet ) );
                return (_xmldocAll.SelectNodes("//status")).Count > 0;
            }
            
            public string Post()
            {
                return Post( this.PostBody );
            }
            
            // returns postid
            public string Post( string strPostBody )
            {
                bool bPublish = true;
                DateTime dtNow = DateTime.Now;
                MetaWeblog.Post post = new MetaWeblog.Post();
                post.title = _settings.titleBlog + " " + (dtNow).ToString("yyyy.MM.dd");
                post.dateCreated = dtNow;
                post.description = strPostBody;
                return _doPost( _settings.idBlog, _settings.useridBlog, _settings.pwdBlog, post, bPublish);
            }
        
            /*
            Settings element attributes:
                hrefget - get: string (must return results as xml; bascially assuming a rest interface)
                useridGet, pwdget - get: authentication = userid, password (yeah, not very secure, need to do something different)
                hrefXsl - transform reference (url; this xslt is applied to the "get" xml, and will result in the post body)
                idBlog - post: destination blog
                useridBlog, pwdBlog - post: authentication (userid, password) (again, security issue)
                titleBlog - post title (appended with date)
                hours - how far back to look
                bPostNone - post when nothing was retrieved ?
            */
            [Serializable()]
            public class Settings
            {
                private string _hrefGet;
                private string _useridGet;
                private string _pwdGet;
                private string _hrefXsl;
                private string _idBlog;
                private string _useridBlog;
                private string _pwdBlog;
                private string _titleBlog;
                private int _intHours;
                private bool _bPostNone;
    
                public Settings() {}
    
                [XmlAttribute("hrefGet")]
                public string hrefGet{get {return this._hrefGet;} set {this._hrefGet = value;}}
    
                [XmlAttribute("useridGet")]
                public string useridGet{get {return this._useridGet;} set {this._useridGet = value;}}
    
                [XmlAttribute("pwdGet")]
                public string pwdGet{get {return this._pwdGet;} set {this._pwdGet = value;}}
    
                [XmlAttribute("hrefXsl")]
                public string hrefXsl{get {return this._hrefXsl;} set {this._hrefXsl = value;}}
    
                [XmlAttribute("idBlog")]
                public string idBlog{get {return this._idBlog;} set {this._idBlog = value;}}
    
                [XmlAttribute("useridBlog")]
                public string useridBlog{get {return this._useridBlog;} set {this._useridBlog = value;}}
    
                [XmlAttribute("pwdBlog")]
                public string pwdBlog{get {return this._pwdBlog;} set {this._pwdBlog = value;}}
    
                [XmlAttribute("titleBlog")]
                public string titleBlog{get {return this._titleBlog;} set {this._titleBlog = value;}}
    
                [XmlAttribute("hours")]
                public int hours{get {return this._intHours;} set {this._intHours = value;}}
    
                [XmlAttribute("bPostNone")]
                public bool bPostNone{get {return this._bPostNone;} set {this._bPostNone = value;}}
            }
    
        }
        
    }
  • fractalnavel.components.cs
    using System;
    using System.IO;
    using System.Net;
    using System.Text;
    using System.Xml;
    using System.Xml.Serialization;
    using System.Xml.Xsl;
    
    namespace fractalnavel.components
    {
    
        public class XmlUtils
        {
            public static string GetTextFromHref(string url, string user, string password)
            {
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
                request.Credentials = new NetworkCredential(user, password);
                WebResponse response = request.GetResponse();
                StreamReader reader = new StreamReader(response.GetResponseStream());
                string responseString = reader.ReadToEnd();
                reader.Close();
                return responseString;
            }
            
            public static string Transform( string strXmlHref, string strXmlUserId, string strXmlPassword, string strXslHref )
            {
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml( GetTextFromHref( strXmlHref, strXmlUserId, strXmlPassword ) );
                return Transform( xmlDoc, strXslHref );
            }
            
            // TODO: add xsl parameter handling
            public static string Transform( XmlDocument xmlDoc, string strXslHref )
            {
                XslTransform xsl = new XslTransform();
                xsl.Load( strXslHref, new XmlUrlResolver() );
                StringBuilder sbResult = new StringBuilder();
                StringWriter swResult = new StringWriter( sbResult );
                xsl.Transform( xmlDoc, null, swResult, null );
                return sbResult.ToString();
            }   
    
            public static Object Deserialize <T> (XmlNode node) 
            {
                XmlSerializer ser = new XmlSerializer( typeof(T) );
                return ser.Deserialize(new XmlNodeReader(node));
            }
    
        }
    
    }
  • Settings.xml
    <?xml version="1.0" encoding="utf-8" ?>
    <!--
        TODO: 
            - use an array of settings nodes for separate services; 
            - specify service handler classs/assembly for items that need programmatic suport (eg, href) 
    -->
    <Settings 
        hrefGet="http://twitter.com/statuses/user_timeline.xml" 
        useridGet="***" 
        pwdGet="***" 
        hrefXsl="*** wherever it was put *** /GetAndPost.xsl" 
        idBlog="*** destination weblog name ***" 
        useridBlog="***" 
        pwdBlog="***" 
        titleBlog="a day in a life" 
        hours="24" 
        bPostNone="false" 
        />
  • GetAndPost.xsl
    <?xml version="1.0" ?>
    <xsl:stylesheet 
        version="1.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:user="http://blogs.no-ip.org/fractalnavel"
        xmlns:msxsl="urn:schemas-microsoft-com:xslt"
        exclude-result-prefixes="xsl user msxsl" 
        >
    
        <xsl:output 
            method='html' 
            omit-xml-declaration="yes"
            version="1.0"
            encoding="UTF-8"
            indent="yes"
            cdata-section-elements=""
            /> 
        
        <!-- TODO: add parameters handling for settings from GetAndPost.Settings class -->
        <xsl:template match="/statuses">
    
            <div class="divLTAll">
    
                <div class="divLTHead">
                    via @<a href="http://www.twitter.com/*** who you are ***" target="_blank" 
                    title="twitter!">*** who you are ***</a>: in the last twenty-four hours:
                </div>
            
                <div class="divLTBody">
                    <ul>
                        <xsl:apply-templates select="status" >
                            <xsl:sort select="position()" order="descending" data-type="number"/>
                        </xsl:apply-templates>
                    </ul>
                </div>
    
                <div class="divLTFoot">
                    (pulled direct from twitter via custom job)
                </div>
                
            </div>
    
        </xsl:template>
    
        <xsl:template match="status">
            <li><span class="spnLTItemDate"><xsl:value-of select="user:fnNormalizeDate(string(created_at))" /></span>: 
            <xsl:value-of select="user:fnSetLinks(string(text))" disable-output-escaping="yes" /></li>
        </xsl:template>
    
        <msxsl:script language="JScript" implements-prefix="user">
        //<![CDATA[
        
        function fnSetLinks( strText )
        {
            // embedded hrefs
            strText = strText.replace( /(http:\/\/\S*)/g, "<a href=\"$1\" class=\"aLTLink\" target=\"_blank\">$1</a>" );
            // twitter ids
            strText = strText.replace( /@(\S*)/g, "@<a href=\"http://www.twitter.com/$1\" class=\"aLTUser\" target=\"_blank\">$1</a>" );
            // hash tags
            strText = strText.replace( /#(\S*)/g, "<a href=\"http://search.twitter.com/search?q=%23$1\" class=\"aLTHash\" target=\"_blank\">$1</a>" );
            return strText;
        }
        
        function fnNormalizeDate(strDate) {
            try {
                // "Mon Mar 16 18:16:59 +0000 2009" to "2009.03.16 18:16": 
                var rxMatch = /.{3} (.{3}) (\d{2}) (\d{2}:\d{2}):\d{2} \+\d{4} (\d{4})/;
                strDate = strDate.replace( rxMatch , 
                    function(strMatch, strMonth, strDay, strTime, strYear)
                    {
                            var dat = new Date( strMonth + " " + strDay + " " + strYear + " " + strTime );
                            // months number is zero based ?!?  wtf
                            strMonth = (dat.getUTCMonth()+1).toString().replace( /^(\d)$/, "0$1" );
                            return strYear + "." + strMonth + "." + strDay + " " + strTime; 
                    });
            } catch(e) {
                strDate = e.message;
            }
            return strDate ;
        }
    
        //]]>
        </msxsl:script>
    
    </xsl:stylesheet>

i also need to reorganize the naming a bit.  i'll reserve commentary until the last revisions are complete.

Posted by fractalnavel at 5:26 PM | with no comments
Filed under: , ,