June 2005 Entries

I'm seeing a little trend - I delete comment spam as soon as it gets to any of my weblogs, so I don't have any hard numbers - posts that I have written about Mike's ReverseDOS sure seem to be getting targeted by comment spammers. I don't see this in the blog that has ReverseDOS installed, but instead at the one hosted on weblogs.asp.net.

What they don't know is that I have comment moderation turned on, so no comments make it thru without my say so. I wonder how many layers of defense will be required before I no longer have to worry about comment spam?

[ Currently Playing : Square One - Coldplay - (4:47) ]

I saw that Jeff got things up and running with PostXING (sorry again about the whole BlogInfo[0] thing) when I looked at the url. What's this? dasBlog? I never knew that dasBlog supported the Metablog API, although I did see the methods exposed from its blogger.aspx page. I thought they were just place holders, but I fired up my local copy of dasBlog and, sure enough, PostXING can post to it.

WordPress also supports the metablog API - hopefully subText will retain that feature of dotText so there will be at least a few blogging engines (I know of) that you can set up for a personal blog and post to with PostXING.

update: It seems it was a fluke on my end, but I have an older version of dasBlog. It sure looks from Jeff's post that it works with whatever version he's running...

[ Currently Playing : White Shadows - Coldplay - (5:28) ]

If you are running your own asp.net blogging engine and you support comments/trackbacks/pingbacks, go get ReverseDOS. Right now. I'll wait.

Back already? Great! Seriously, ever since installing ReverseDOS, I have yet to see one auto-generated comment, when I used to get about 50 a day. Worse on weekends. Here are a couple of lines that I added to the ruleset:

<add type="post" pattern="poker" action="403" />
<add type="post" pattern="blackjack" action="403" />

Simple, right? It's usually the dead simple ideas that are the most elegant solutions in the end. Thanks, Mike.

[ Currently Playing : Star Spangled Banner - Jimi Hendrix - (3:47) ]

posted @ Thursday, June 23, 2005 11:30 PM | Feedback (0) | Filed Under [ .NET ]

So I got some feedback about PostXING saying that someone who had setup multiple blogs with CS::Blogs was getting the wrong blog back while trying to communicate with the Metaweblog API.

After a couple of questions, it turns out that all of the users were set up as sysadmins in the CS permission set, so anyone making a request to the metablog api would get a list of all the blogs available. Since PostXING ignorantly just uses BlogInfo[0] from the metablog_getUsersBlogs() method, everybody was trying to post to the first blog returned in the list.

So if you are running a multiple blog setup and wish to use the metablog api, make sure that your permissions are set so that when a user makes a request into his/her blog, theirs is the only blog they get back.

Thanks, Jeff.

[ Currently Playing : Voodoo Child (Slight Return) - Jimi Hendrix - (5:12) ]

I feel like I'm going nuts with interfaces in the next version of PostXING. Interfaces are a language feature that is really powerful - you don't really start to appreciate it until you are faced with situations that would otherwise be impossible to deal with.

PostXING already uses interfaces to load plugins like the NetSpellPlugin for spell checking. So I thought hey, go with what you know for this plugin/provider idea that I've had stewing in my head for a while. I've already included MikeDub's awesome IUI library (modified with - you guessed it, interfaces!) so I figured I might as well milk that for all it's worth. And trust me, I am :)

The idea I have is to use IUI to set up a new/edit an existing "blog" (what PostXING sees as a blog) and let each plugin/provider take care of any special configuration they might need. But there's a problem - every provider should have common attributes defined within the interface, but there is also non-blog information that I would like to store (like ftp settings, whether or not you want media information to show up like below (I know, Alice in Chains again - I just write good code to that CD), and preview formatting).

So, how do I communicate that the custom IUI pages are done so that the rest of the configuration can continue? Well, I could use a vanilla EventHandler event, but how can I make sure that the main exe project will be able to handle the event without knowing which provider has been loaded? Furthermore, how can the provider send up an event for it to catch without having a reference to the main exe project (a circular dependency - nono!)?

Interfaces.

I create an interface that only the dialog that shows the configuration pages should implement. It could be a simple interface with only 1 to 3 methods defined for it (if I want to only expose moving forward to one page vs. moving to any available page thereafter)...see what I'm getting at? Maybe some code will better explain what I'm getting at:

using System;
using System.Collections;

public interface IFoo{
	void HandleEvent(object sender, EventArgs e);
}

public class FooInstance : IFoo{
	public void HandleEvent(object sender, EventArgs e){
		System.Windows.Forms.MessageBox.Show("Handled! Booyakasha!");
	}
}

public class MyClass
{
	public static void Main()
	{
		IFoo thisfoo = new FooInstance();
		
		MyClass s = new MyClass();
		
		s.WireUpEvent(thisfoo);
		
		if(s.throwevent != null){
			s.throwevent(s, EventArgs.Empty);
		}
	}
	public event EventHandler throwevent;
	
	public void WireUpEvent(IFoo foo){
		this.throwevent += new EventHandler(foo.HandleEvent);
	}
}

This was a little POC that I coded up in snippet compiler - and yes, it compiles and runs wonderfully. Booyakasha indeed. Here, IFoo is the interface that is implemented by the dialog. Passing the concrete FooInstance (the dialog) to the method WireUpEvent of what will be the provider class works thanks to wonderful, wonderful interfaces.

[ Currently Playing : Nutshell - Alice in Chains - Unplugged (4:57) ]

Tina asked me to learn this Paul McCartney song...so I cheated :)

That's it. This was purely so I didn't forget the url. Nothing technical to see here.

Here is some of the common ground I can see between the metaweblog api and CS::Blogs BlogService asmx.

Blog/Authentication:

  • UserName
  • Password
  • BlogID/BlogName

Post/Entry:

  • DateCreated/Date
  • Description/Body
  • Title
  • string[] Categories (nice!)
  • PostID

Non-Conformities (for Posts):

  • Metablog API
    • Enclosure (although this is not used by CS::Blogs or .Text)
    • link
    • permalink
    • Source (name and url, was supported by .Text, not so sure about CS::Blogs)
    • userid
  • BlogService.asmx
    • Excerpt
    • Name (I guess this is for url rewriting)
    • Enable Comments
    • Enable Trackbacks
    • Moderate Comments
    • Enable Ratings
    • Syndicate
    • Syndicate Excerpt (I guess you have to define an excerpt for this to work?)
    • Syndicate Root (for communities?)
    • DisplayOnHome (again, communities?)
    • IsArticle (I really dig this one. I've wanted to be able to edit articles from the desktop for a long time.)

I've also been looking at ATOM a little bit - there doesn't seem to be any mention of categories in atom, which kinda sucks considering categories are a nice way to filter content.

All of the apis, including atom, have one other thing in common: getting general blog information is usually a two-step process. As an end user, I must supply a username, a password, and a url (although the atom api lets you enter a homepage url with a <link/> element that points to the service url (v1.0 of CS::Blogs asks for a blogname, too. Maybe this says that you should only work with one blog at a time?)). Then I get a list of blogs that I can edit with the credentials supplied. Then I can create, update, or delete a post. I can also get a list of recent entries (and articles in the case of the BlogService.asmx).

With atom, on blogger at least, you are required to use https:// as the uri scheme. Not a big deal, this just means that the common denominator for a blog has to have a couple of booleans: UseSSL and SupportsCategories, because those two are what separates atom and the apis of CS::Blogs from a coding standpoint. Since I'm going to be using libraries to handle the xml transfers (xml-rpc, soap, or rest) I could care less what the xml looks like.

Speaking of libraries, the code that I have for handling the metaweblog api also includes support for the old blogger xml-rpc api (thanks, dasBlog!), so I'll probably include support for posting to that api as well in the new version of PostXING.

After another slew of referrer/comment spam that showed up in my blog this morning, I went ahead and downloaded Mike's ReverseDOS.

I followed the steps outlined for setup, but it didn't quite work the way it was outlined at first - I got the dreaded "yellow screen of death". This was due to the entries that I had made in the web.config. So I looked at the entries that were already in there, and I noticed that some <section/> nodes were added to the <system.web/> node. Moving the default configuration from looking like this:

<!-- copy and paste the following code -->
<configSections>
   <sectionGroup name="AngryPets" >
      <section name="ReverseDOS" type="AngryPets.Web.Frameworks.ReverseDOS.FilterConfigHandler, AngryPets.Web.Frameworks.ReverseDOS" />
   </sectionGroup>
</configSections>

Instead, mine now looks like this:

<sectionGroup name="system.web">
	<section name="membership" type="Microsoft.ScalableHosting.Configuration.MembershipConfigHandler, MemberRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7c773fb104e7562"/>
	<section name="roleManager" type="Microsoft.ScalableHosting.Configuration.RolesConfigHandler, MemberRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7c773fb104e7562"/>
	<section name="profile" type="Microsoft.ScalableHosting.Configuration.ProfileConfigHandler, MemberRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7c773fb104e7562"/>
	<section name="anonymousIdentification" type="Microsoft.ScalableHosting.Configuration.AnonymousIdConfigHandler, MemberRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7c773fb104e7562"/>
	<section name="ReverseDOS" type="AngryPets.Web.Frameworks.ReverseDOS.FilterConfigHandler, AngryPets.Web.Frameworks.ReverseDOS" />
</sectionGroup>

And I of course moved the ReverseDOS node to be under system.web. We'll see how this pans out, but I thought I would put it out there just in case someone else was having issues with it.

[ Currently Playing : Stinkfist - Tool - Aenima (5:10) ]

Nice! Lookin good, Don! I personally have had firewall issues with FTP (what a beast!) and have yet to find an opensource SFTP (ftp as a subset of ssh) solution, which does work on my server. One of these days I'm going to beef up my firewalling skills and let the stinkin ftp traffic thru.

Anyways, glad to see you "back in the game" :)

In an attempt to get back on top of my blogging, I've just installed the latest release of Christopher's PostXING, all of its plugins, and configured the FTP support. If this post is successful, I (and you) will know I'm good to go.

This is one of my MSN Instant Messenger avatars. It's supposed to look like me ;-)

[Currently Playing :: Louder Than Words - Greenwheel]

[Via Don Smith (dev4net)]

Yex sez:

 Nice. So where's the Categories, Post, Post and Publish and Crosspost buttons at? Where's the post editing toolbar? When can we get our grubby little hands on it?

Since it appears you've decided to go with the whole sidebar idea, why not use that to list the cateogories checkboxes? Seems logical to me anyway.

Yex

Good questions! I've actually created a sidebar for the categories, and am currently studying a couple of the API's I want to support right away - it looks like I will be able to handle categories the same way that I do currently. I'm going to try and find a way to push categories into the file that is saved (er..File -> Save) for a better offline story too.

I'm also looking to remove the History dialog and replace it with a "view" on the main form - no reason other than trying to get rid of unnecessary dialogs. And it'll look cool :)

As far as all of the other buttons, my current plan is to have all of that plus some configuration details pushed off to a kind of "provider" - each api plugin should know what buttons it wants to add, what operations those buttons support, what kind of identifying information the api needs, etc.

I'm hoping that I'll be able to break things down to a common denominator and have something that will be able to tailor the UI to the current blog that is being edited.

And as far as the grubby hands, sorry - it's probably going to be a little while before this is ready for prime time. I'm not even ready to dogfood v2 yet. :(

[ Currently Playing : Would? - Alice in Chains - Unplugged (3:42) ]

Thanks to Alex, I checked out a great application of Greasemonkey - the Gmail Delete Button.

Of course, I had to look at the script since it's just javascript and play with it to see if I could extend it a little bit.

As with most of my "embrace and extend" forays, it was just a simple change - I use a lot of labels in gmail, so when I'm reading via the web interface, I have some organization to the 50+ email lists I'm a member of. Every screen that has conversations listed on it has a delete button, including the search view, except for labels (until you hit the search mail button, but then the number of visible conversations goes from 50 to 20).

So, I popped open the "view frame info" context menu item from gmail and saw that the view querystring parameter for a label was tl. With that in mind:

if (document.location.search) {
	if (document.location.search.match(/search=inbox/)
		||
		document.location.search.match(/search=query/)
		||
		document.location.search.match(/view=tl/) &&
		!document.location.search.match(/search=trash/)
		||
		document.location.search.match(/view=cv/) && 
		!document.location.search.match(/search=trash/)
	) {
		setInterval('try{window._gd_place_delete_buttons();}catch(e){}', 25);
	}
}

I'm not sure if the  && !document.location... part that I added is necessary, but it doesn't hurt anything. Now I can delete posts in all of the views that I would want to in gmail.

I didn't go too too far, I think. It's definitely a step in the right direction, tho:

I don't know why I've opted to start at the top and go down...probably because I'm just procrastinating on getting to the meat & potatoes (!) problems. I also had to go into a different program to upload the file above...I'll be checking that as well.

I've been working a little on my plugin/provider idea on PostXING. Currently, I have it building, but I've had to disable some of the post-build commands because although it builds, it doesn't do anything currently and I don't want it to overwrite the working copy that I have on my computer.

Interesting aside: I didn't actually remove the commands, but since they are all written to a .bat file, you can use normal batch commands - like rem - to effectively disable the commands. An example that is currently disabled in the branch .csproj file but not in the main trunk:

rem COPY /Y $(ProjectDir)ReadMe.txt $(TargetDir)ReadMe.txt

This way, when I'm ready to actually dogfood my new creation, I just need to remove the rem's and I'm good to go.

I've only made progress on the UI so far, but if you want to see the progress, the code is always available on vaultpub. You can view everything on the web over here: the login is guest/guest.

As if you cared...

I'm still trying to work out how cross-posting should be implemented. I've decided to go with an interface-driven plugin model because I don't have an app.config with this app (no reason for that - just haven't needed it yet) and I've already got 2 types of interfaces loading as plugins. I have 3(1/2) different types of plugin/providers that I want to implement, all of which I have access to so I can at least test it a little bit. They will include providers using xml-rpc, webservices, and the Atomizer. On the UI side, I'm going to do away with as many dialogs as possible. I'm trying to have this app have only one or two dialogs where it makes sense. I think everything else should just be a "view" on the main form.

I've also imported a couple of controls to the project along with an IUI library so different "views" shouldn't be too hard to implement I think. Anyways, back to coding...

posted @ Friday, June 10, 2005 6:28 PM | Feedback (0) | Filed Under [ PostXING ]