RssSmtpSink.cs :  » RSS-RDF » Aggie » Bitworking » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » RSS RDF » Aggie 
Aggie » Bitworking » RssSmtpSink.cs
using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Xml;
using Bitworking.Smtp;
 
namespace Bitworking{

  public class MailHeaderAndBody {
    public string from;
    public string subject;
    public string to;
    public StringBuilder body;
  }

public class RssSmtpSink : IRssSink {
  // These fields are not really instace fields.
  // They are scratch-pad fields used to pass state
  // between implementation functions to reduce argument count.
  private string title_;
  private string link_;
  private string description_;
  private string baseUrl_;
  private string parserComments_;

  // Default SMTP envelope
  private string from_;
  private string to_;
  private string via_;

  public void NewAggregatedXml(bool freshFeeds) {
    // Note: Emailer doesn't send mail on read items,
    //       regardless of the state of the
    //       "show old items" checkbox.
    //       The following control is useful for debugging.
    bool forceEmailGenerationForReadItems = false;

    if (freshFeeds) {
      SmtpConfigInfo config = new SmtpConfigInfo();
      SerializeByAttributes.Read(config, "Aggie.xfg");
      if (config.enableMailer) {
        SetDefaultEnvelope( config );
        SmtpBatchMailer batchMailer = new SmtpBatchMailer( config );
        string itemSelectionPath = 
          (forceEmailGenerationForReadItems ? "item" : "item[@read='false']");
        string channelSelectionPath = "channel";
        string siteSelectionPath = "//aggregate/site";

        XmlDocument doc = new XmlDocument();
        doc.Load("aggregated.xml");
        XmlNodeList sites = doc.SelectNodes(siteSelectionPath);
        foreach (XmlNode site in sites) {

          XmlNode channel = site.SelectSingleNode(channelSelectionPath);
          if (null != channel) {
            title_       = GetElementValue(channel, "title");
            link_       = GetElementValue(channel, "link");
            description_   = GetElementValue(channel, "description");
            baseUrl_     = GetElementValue(channel, "base");
            parserComments_ = GetElementValue(channel, "comments");

            // TODO: There must be a nicer way to do this:
            if ( parserComments_ != "" ) {
              parserComments_ = parserComments_.Replace( "<strict>",  "<p>[Strict parser] " );
              parserComments_ = parserComments_.Replace( "</strict>", "</p>\r\n" );
              parserComments_ = parserComments_.Replace( "<loose>",   "<p>[Loose parser] " );
              parserComments_ = parserComments_.Replace( "</loose>",  "</p>\r\n" );
            }

            XmlNodeList items = site.SelectNodes(itemSelectionPath);
            if ( null != items ){
              NewAggregatedChannel( config, batchMailer, items );
            }
          }
        }    
        batchMailer.Close();
      }
    }
  } // NewAggregatedXml

  private void NewAggregatedChannel(
    SmtpConfigInfo config,
    SmtpBatchMailer batchMailer,
    XmlNodeList items ) {

    // We have, say, M items in the channel, and need to group them into N
    // groups. How this grouping is done is controlled by a config option:
    // 1. Each item is in its own mail message (N=M)
    // 2. All items are in a single mail message (N=1)
    // 3. Items are grouped according to some criteria.
    //    Currently that criteria is the item title.
    bool reverseItems = config.reversItems;
    int howToGroup = config.howToGroup;

    // Make a modifieable list of items
    // TODO: (ZivC) Must be a better way to do this in .NET
    ArrayList itemsList = new ArrayList();
    foreach (XmlNode node in items) {
      itemsList.Add( node );
    }

    // Reverse items if necessary
    if ( reverseItems )
      itemsList.Reverse();

    MailHeaderAndBody msg;

    switch ( howToGroup ) {
      case 0: // N=M
        foreach ( XmlNode node in itemsList ) {
          ComposeMailFromItem( node, out msg );
          MailItem( config, batchMailer, msg );
        }
        break;

      case 1: // N=1
        ComposeMailHeader( "", "", out msg );
        foreach ( XmlNode node in itemsList ) {
          ComposeMailItem( node, ref msg );
        }
        ComposeMailFooter( ref msg );
        MailItem( config, batchMailer, msg );
        break;

      case 2: // Group by title
        while ( itemsList.Count > 0 ) {
          ArrayList group = new ArrayList();
          group.Add( itemsList[0] );
          itemsList.RemoveAt( 0 );
          string title = GetElementValue((XmlNode)group[0], "title");
                    
          int other = 0;
          while ( other < itemsList.Count ) {
            string otherTitle = GetElementValue((XmlNode)itemsList[other], "title" );
            if ( title == otherTitle ) {
              group.Add( itemsList[other] );
              itemsList.RemoveAt( other );
            }
            else
              other++;
          }

          ComposeMailHeader( title, "", out msg );
          foreach ( XmlNode node in group ) {
            ComposeMailItem( node, ref msg );
          }
          ComposeMailFooter( ref msg );
          MailItem( config, batchMailer, msg );
        } // while more items to process
        break;
    } // switch
  } // NewAggregatedChannel


  private string GetElementValue(XmlNode node, string path) {
    string returnValue = "";
    XmlNode target = node.SelectSingleNode(path);
    if (null != target) {
      string encoded = target.InnerXml;
      returnValue = System.Web.HttpUtility.HtmlDecode( encoded );
    }
    return returnValue;
  } // GetElementValue

  private void SetDefaultEnvelope( SmtpConfigInfo config ) {
    string sendingAccount   = StringUtils.StringOrFallback( config.sendingAccount, "" );
    string receivingAccount = StringUtils.StringOrFallback( config.receivingAccount, sendingAccount );

    // Wrap account names with a "<...>" envelope if required
    if ( sendingAccount.IndexOf( "<" ) < 0 )
      sendingAccount = "<" + sendingAccount + ">";
    if ( receivingAccount.IndexOf( "<" ) < 0 )
      receivingAccount = "<" + receivingAccount + ">";

    from_ = "Aggie " + sendingAccount;
    to_   = "Aggie " + receivingAccount;
    via_  = " (via Aggie)\" " + sendingAccount;
  } // SetDefaultEnvelope

  private void ComposeMailHeader( string itemTitle, string itemLink, out MailHeaderAndBody msg ) {
    msg = new MailHeaderAndBody();
    // 'From' field
    // TODO: I don't like this. What if title_ has a " ?
    //       I need to think of a better solution here. (ZivC)
    if ( title_ != "" ) {
      msg.from = "\"" + title_ + via_;
    } else {
      msg.from = from_;
    }

    // 'Subject' field
    if ( itemTitle != null && itemTitle != "" ) {
      msg.subject = itemTitle;
    } else if ( itemLink != null && itemLink != "" ) {
      msg.subject = "New post from " + title_ +  " (" + itemLink + ")";
    } else {
      msg.subject = "New post from " + title_;
    }

    // 'To' field
    msg.to = to_;

    // We must make sure that the RFC 2822 headers do not have
    // any HTML-encoded character.
    // TODO: (ZivC) Do we really need this? Don't we do HtmlDecode before processing?
    msg.from    = System.Web.HttpUtility.HtmlDecode( msg.from    );
    msg.subject = System.Web.HttpUtility.HtmlDecode( msg.subject );
    msg.to      = System.Web.HttpUtility.HtmlDecode( msg.to      );

    // Body
    // Massage the body to appear better
    msg.body = new StringBuilder();
    msg.body.Append( ""
      +"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://w3.org/TR/xhtml11/DTD/xhtml1-transitional.dtd\">\r\n"
      +"<html>\r\n"
      +"  <head>\r\n"
      +"    <style type='text/css'>\r\n"
      + GetStylesheet()
      +"    </style>\r\n"
      +((baseUrl_ != "") ? "    <base href='" + baseUrl_ + "'/>\r\n" : "")
      +"  </head>\r\n"
      +"  <body>\r\n" );

    if ( parserComments_ != "" ) {
      msg.body.AppendFormat(
        "<p style='color: red'>The following information was salvaged from the feed.\r\n"
        + " Please forward the error description (found at the bottom of this page)"
        + " to the feed's provider.</p><hr />\r\n" );
    }

  } // ComposeMailHeader

  private void ComposeMailFooter( ref MailHeaderAndBody msg ) {
    msg.body.AppendFormat( "\r\n<p class='channeldata'>Channel: {0}\r\n", title_ );

    if ( link_ != "" ) {
      msg.body.AppendFormat( "<br />Link: <a href='{0}'>{0}</a>\r\n", link_ );
    }

    if ( description_ != "" ) {
      msg.body.AppendFormat( "<br />Description: {0}\r\n", description_ );
    }

    msg.body.Append( "<br />Mail sent by <a href='http://bitworking.org/Aggie.html'>Aggie</a>.</p>\r\n" );

    if ( parserComments_ != null && parserComments_ != "" ) {
      msg.body.AppendFormat( "<hr /><p style='color: red'>Error description:</p>\r\n"
        + "<p style='color:red'>{0}</p>\r\n", parserComments_ );
    }
        
    msg.body.Append( "  </body>\r\n</html>\r\n" );
  } // ComposeMailFooter

  private void ComposeMailItem( XmlNode node, ref MailHeaderAndBody msg ) {
    string itemTitle       = GetElementValue(node, "title");
    string itemLink        = GetElementValue(node, "link");
    string itemDescription = GetElementValue(node, "description");
    string itemDate        = GetElementValue(node, "date");

    // Note: We don't need to call StringUtils.StringOrFallback( *,  "" ) here,
    //       as GetElementValue does this for us.

    // Channel information is stored in instance data: title_, link_, description_.
    // Item information is stored in formal arguments: itemTitle, itemLink, itemDescription.
    //
    // Mail appears as if sent from sender: "title_ (via Aggie)" <user@userhost>.
    // Mail subject if item has a title: itemTitle,
    //   If has a link: itemLink,
    //     Otherwise: New post from title_.

    ComposeMailItem( node, ref msg, itemTitle, itemLink, itemDescription, itemDate );
  } // ComposeMailItem

  private void ComposeMailItem( XmlNode node, ref MailHeaderAndBody msg, string itemTitle, string itemLink, string itemDescription, string itemDate ) {
    // Body
    
    msg.body.Append( "<div>\r\n" ); // Wrapper

    // Massage the body to appear better
    if ( itemTitle != "" ) {
      if ( itemLink != "" ) {
        msg.body.AppendFormat( "<h1><a href='{1}'>{0}</a></h1>\r\n", itemTitle, itemLink );
      } else {
        msg.body.AppendFormat( "<h1>{0}</h1>\r\n", itemTitle );
      }          
    }

    if ( itemLink != "" ) {
      msg.body.AppendFormat( "<p class='rsslink'>Link: <a href='{0}'>{0}</a></p>\r\n", itemLink );
    }

    if ( itemDate != "" ) {
      msg.body.AppendFormat( "<p class='rssdate'>Date: {0}</p>\r\n", itemDate );
    }

    msg.body.Append( itemDescription );

    msg.body.Append( "\r\n</div>\r\n" ); // Wrapper

  } // ComposeMailItem

  private void ComposeMailFromItem( XmlNode node, out MailHeaderAndBody msg ) {
    string itemTitle       = GetElementValue(node, "title");
    string itemLink        = GetElementValue(node, "link");
    string itemDescription = GetElementValue(node, "description");
    string itemDate        = GetElementValue(node, "date");

    ComposeMailHeader( itemTitle, itemLink, out msg );

    ComposeMailItem( node, ref msg, itemTitle, itemLink, itemDescription, itemDate );

    ComposeMailFooter( ref msg );

  } // ComposeMailFromItem

  private void MailItem( SmtpConfigInfo config, SmtpBatchMailer batchMailer, MailHeaderAndBody msg ) {
    if ( config.enableMailer ) {
      bool enableMailer = config.enableMailer; // Anchor for debug breakpoints

      SmtpMailItem mail = new SmtpMailItem();

      mail.Body = msg.body.ToString();
      mail.ContentTransferEncoding = ContentTransferEncoding.base64;
      mail.From = msg.from;  
      mail.SendAsHtml = true;
      mail.Subject = msg.subject;
      mail.Recipients.Add( msg.to );
      try {
        //System.Diagnostics.Debug.WriteLine( "....Mail item to follow...." );
        //System.Diagnostics.Debug.WriteLine( mail.Body );

        if ( enableMailer ) {
          batchMailer.SubmitItemForSending( mail );
        }
      }
      catch ( System.Exception ) {
      }
    }
  } // MailItem

  // Embedded stylesheet support (by Tim Danner)
  private const string STYLESHEET_FILENAME = "email.css";
  private const string DEFAULT_STYLESHEET_FILENAME = "email.css.orig";

  private string mailStylesheet_;

  private string GetStylesheet() {
    if (mailStylesheet_ == null) {
    
      // Attempt to load email.css. Return its contents if successful, 
      // otherwise return a default stylesheet.

      if (File.Exists(DEFAULT_STYLESHEET_FILENAME) && !File.Exists(STYLESHEET_FILENAME)) {
        File.Copy(DEFAULT_STYLESHEET_FILENAME, STYLESHEET_FILENAME);
      }

      try {
        using (StreamReader css_stream = new StreamReader(STYLESHEET_FILENAME)) {
          mailStylesheet_ = css_stream.ReadToEnd();
        }
      }
      catch (System.Exception) {
        mailStylesheet_ = "";
      }
    }

    return mailStylesheet_;
  }


}

}
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.