Files
duplicati/thirdparty/DnsLite/DnsLite.cs
T
kenneth@hexad.dk 6822fc69fa Update issue #29
This adds the email feature to Duplicati.
Currently there is no GUI for this, just advanced options.
The options supported are:
--send-mail-to="Name <test@example.com>, Other <test2@example.com>, test3@example.com"
--send-mail-from="Backup Admin <admin@example.com>
--send-mail-subject="Duplicati %OPERATIONNAME% Report"
--send-mail-body="%RESULT%%"
--send-mail-url="tls://smtp.google.com:587"
--send-mail-username="username"
--send-mail-password="password"
--send-mail-level="Warning"
--send-mail-any-operation=true

The only required setting is --send-mail-to.
If the --send-mail-from is not set, it will use the host of the "to" and set "no-reply@" in front.
E.g. --send-mail-to="name@example.com" will cause the sender to be "no-reply@example.com".

If the --send-mail-url is not set, a DNS lookup will find the MX record for the first recipient domain,
and send directly to that. The url can be either "smtp://server:port" or "tis://server:port".

The --send-mail-subject and --send-mail-body parameters can contain placeholders like %RESULT%.
Each option will be exported like this, e.g. %volsize% or %use-ssl%. The special placeholders are:
%RESULT% - The result/log of the backup
%OPERATIONNAME% - The name of the operation, usually "Backup", but could be "Restore" etc.
%REMOTEURL% - The backend url
%LOCALPATH% - The path to the local folders involved (i.e. the folders being backed up)

The --send-mail-level can be either "Success", "Warning" or "Error". Default "Success" means all backups generate an email. "Warning" will only send an email if the backup caused a warning or an error. "Error" will only send an email if the backup failed.

The --send-mail-any-operation can be set to "true" if all operations (e.g. "Restore", "Cleanup", "DeleteAllButN", ...) should generate an email. By default only backup operations will send an email.

git-svn-id: https://duplicati.googlecode.com/svn/trunk@1436 59da171f-624f-0410-aa54-27559c288bec
2012-08-21 09:35:55 +00:00

172 lines
4.9 KiB
C#

//Dnslite.cs
/**
csc /target:library /out:DnsLib.dll /keyfile:..\..\Duplicati\GUI\Duplicati.snk DnsLite.cs
*/
using System;
using System.Net;
using System.IO;
using System.Text;
using System.Net.Sockets;
using System.Collections;
namespace DnsLib
{
public class MXRecord
{
public int preference = -1;
public string exchange = null;
public override string ToString()
{
return "Preference : " + preference + " Exchange : " + exchange;
}
}
public class DnsLite
{
private byte[] data;
private int position, id, length;
private string name;
private ArrayList dnsServers;
private static int DNS_PORT = 53;
Encoding ASCII = Encoding.ASCII;
public DnsLite()
{
id = DateTime.Now.Millisecond * 60;
dnsServers = new ArrayList();
}
public void setDnsServers(ArrayList dnsServers)
{
this.dnsServers = dnsServers;
}
public ArrayList getMXRecords(string host)
{
ArrayList mxRecords = null;
for(int i=0; i < dnsServers.Count; i++)
{
try
{
mxRecords = getMXRecords(host,(string)dnsServers[i]);
break;
}
catch(IOException)
{
continue;
}
}
return mxRecords;
}
private int getNewId() {
//return a new id
return ++id;
}
public ArrayList getMXRecords(string host,string serverAddress) {
//opening the UDP socket at DNS server
//use UDPClient, if you are still with Beta1
UdpClient dnsClient = new UdpClient(serverAddress, DNS_PORT);
//preparing the DNS query packet.
makeQuery(getNewId(),host);
//send the data packet
dnsClient.Send(data,data.Length);
IPEndPoint endpoint = null;
//receive the data packet from DNS server
data = dnsClient.Receive(ref endpoint);
length = data.Length;
//un pack the byte array & makes an array of MXRecord objects.
return makeResponse();
}
//for packing the information to the format accepted by server
public void makeQuery(int id,String name) {
data = new byte[512];
for(int i = 0; i < 512; ++i)
{
data[i] = 0;
}
data[0] = (byte) (id >> 8);
data[1] = (byte) (id & 0xFF );
data[2] = (byte) 1; data[3] = (byte) 0;
data[4] = (byte) 0; data[5] = (byte) 1;
data[6] = (byte) 0; data[7] = (byte) 0;
data[8] = (byte) 0; data[9] = (byte) 0;
data[10] = (byte) 0; data[11] = (byte) 0;
string[] tokens = name.Split(new char[] {'.'});
string label;
position = 12;
for(int j=0; j < tokens.Length; j++) {
label = tokens[j];
data[position++] = (byte) (label.Length & 0xFF);
byte[] b = ASCII.GetBytes(label);
for(int k=0; k < b.Length; k++) {
data[position++] = b[k];
}
}
data[position++] = (byte) 0 ; data[position++] = (byte) 0;
data[position++] = (byte) 15; data[position++] = (byte) 0 ;
data[position++] = (byte) 1 ;
}
//for un packing the byte array
public ArrayList makeResponse() {
ArrayList mxRecords = new ArrayList();
MXRecord mxRecord;
//NOTE: we are ignoring the unnecessary fields.
// and takes only the data required to build MX records.
int qCount = ((data[4] & 0xFF) << 8) | (data[5] & 0xFF);
if (qCount < 0) {
throw new IOException("invalid question count");
}
int aCount = ((data[6] & 0xFF) << 8) | (data[7] & 0xFF);
if (aCount < 0) {
throw new IOException("invalid answer count");
}
position=12;
for( int i=0;i<qCount; ++i) {
name = "";
position = proc(position);
position += 4;
}
for (int i = 0; i < aCount; ++i) {
name = "";
position = proc(position);
position+=10;
int pref = (data[position++] << 8) | (data[position++] & 0xFF);
name="";
position = proc(position);
mxRecord = new MXRecord();
mxRecord.preference = pref;
mxRecord.exchange = name;
mxRecords.Add(mxRecord);
}
return mxRecords;
}
private int proc(int position) {
int len = (data[position++] & 0xFF);
if(len == 0) {
return position;
}
int offset;
do {
if ((len & 0xC0) == 0xC0) {
if (position >= length) {
return -1;
}
offset = ((len & 0x3F) << 8) | (data[position++] & 0xFF);
proc(offset);
return position;
} else {
if ((position + len) > length) {
return -1;
}
name += ASCII.GetString(data, position, len);
position += len;
}
if (position > length) {
return -1;
}
len = data[position++] & 0xFF;
if (len != 0) {
name += ".";
}
}while (len != 0);
return position;
}
}
}