1 // Copyright 2007 Alp Toker <alp@atoker.com> 2 // This software is made available under the MIT License 3 // See COPYING for details 4 5 using System; 6 using System.Text; 7 using System.Collections.Generic; 8 9 namespace NDesk.DBus 10 { 11 //delegate void MessageHandler (Message msg); 12 13 class MatchRule 14 { 15 public MessageType? MessageType; 16 public string Interface; 17 public string Member; 18 public ObjectPath Path; 19 public string Sender; 20 public string Destination; 21 public readonly SortedDictionary<int,string> Args = new SortedDictionary<int,string> (); 22 MatchRule()23 public MatchRule () 24 { 25 } 26 Append(StringBuilder sb, string key, string value)27 void Append (StringBuilder sb, string key, string value) 28 { 29 if (sb.Length != 0) 30 sb.Append (","); 31 32 sb.Append (key + "='"); 33 sb.Append (value); 34 sb.Append ("'"); 35 } 36 AppendArg(StringBuilder sb, int index, string value)37 void AppendArg (StringBuilder sb, int index, string value) 38 { 39 Append (sb, "arg" + index, value); 40 } 41 Equals(object o)42 public override bool Equals (object o) 43 { 44 MatchRule r = o as MatchRule; 45 46 if (r == null) 47 return false; 48 49 if (r.MessageType != MessageType) 50 return false; 51 52 if (r.Interface != Interface) 53 return false; 54 55 if (r.Member != Member) 56 return false; 57 58 //TODO: see why path comparison doesn't work 59 if (r.Path.Value != Path.Value) 60 //if (r.Path != Path) 61 return false; 62 63 if (r.Sender != Sender) 64 return false; 65 66 if (r.Destination != Destination) 67 return false; 68 69 //FIXME: do args 70 71 return true; 72 } 73 GetHashCode()74 public override int GetHashCode () 75 { 76 //FIXME: not at all optimal 77 return ToString ().GetHashCode (); 78 } 79 ToString()80 public override string ToString () 81 { 82 StringBuilder sb = new StringBuilder (); 83 84 if (MessageType != null) 85 Append (sb, "type", MessageFilter.MessageTypeToString ((MessageType)MessageType)); 86 87 if (Interface != null) 88 Append (sb, "interface", Interface); 89 90 if (Member != null) 91 Append (sb, "member", Member); 92 93 if (Path != null) 94 //Append (sb, "path", Path.ToString ()); 95 Append (sb, "path", Path.Value); 96 97 if (Sender != null) 98 Append (sb, "sender", Sender); 99 100 if (Destination != null) 101 Append (sb, "destination", Destination); 102 103 if (Args != null) { 104 foreach (KeyValuePair<int,string> pair in Args) 105 AppendArg (sb, pair.Key, pair.Value); 106 } 107 108 return sb.ToString (); 109 } 110 111 //this is useful as a Predicate<Message> delegate Matches(Message msg)112 public bool Matches (Message msg) 113 { 114 if (MessageType != null) 115 if (msg.Header.MessageType != MessageType) 116 return false; 117 118 object value; 119 120 if (Interface != null) 121 if (msg.Header.Fields.TryGetValue (FieldCode.Interface, out value)) 122 if ((string)value != Interface) 123 return false; 124 125 if (Member != null) 126 if (msg.Header.Fields.TryGetValue (FieldCode.Member, out value)) 127 if ((string)value != Member) 128 return false; 129 130 if (Path != null) 131 if (msg.Header.Fields.TryGetValue (FieldCode.Path, out value)) 132 //if ((ObjectPath)value != Path) 133 if (((ObjectPath)value).Value != Path.Value) 134 return false; 135 136 if (Sender != null) 137 if (msg.Header.Fields.TryGetValue (FieldCode.Sender, out value)) 138 if ((string)value != Sender) 139 return false; 140 141 if (Destination != null) 142 if (msg.Header.Fields.TryGetValue (FieldCode.Destination, out value)) 143 if ((string)value != Destination) 144 return false; 145 146 //FIXME: do args 147 148 return true; 149 } 150 151 //this could be made more efficient Parse(string text)152 public static MatchRule Parse (string text) 153 { 154 MatchRule r = new MatchRule (); 155 156 foreach (string propStr in text.Split (',')) { 157 string[] parts = propStr.Split ('='); 158 159 if (parts.Length < 2) 160 throw new Exception ("No equals sign found"); 161 if (parts.Length > 2) 162 throw new Exception ("Too many equals signs found"); 163 164 string key = parts[0].Trim (); 165 string value = parts[1].Trim (); 166 167 if (!value.StartsWith ("'") || !value.EndsWith ("'")) 168 throw new Exception ("Too many equals signs found"); 169 170 value = value.Substring (1, value.Length - 2); 171 172 if (key.StartsWith ("arg")) { 173 int argnum = Int32.Parse (key.Remove (0, "arg".Length)); 174 175 if (argnum < 0 || argnum > 63) 176 throw new Exception ("arg match must be between 0 and 63 inclusive"); 177 178 if (r.Args.ContainsKey (argnum)) 179 return null; 180 181 r.Args[argnum] = value; 182 183 continue; 184 } 185 186 //TODO: more consistent error handling 187 switch (key) { 188 case "type": 189 if (r.MessageType != null) 190 return null; 191 r.MessageType = MessageFilter.StringToMessageType (value); 192 break; 193 case "interface": 194 if (r.Interface != null) 195 return null; 196 r.Interface = value; 197 break; 198 case "member": 199 if (r.Member != null) 200 return null; 201 r.Member = value; 202 break; 203 case "path": 204 if (r.Path != null) 205 return null; 206 r.Path = new ObjectPath (value); 207 break; 208 case "sender": 209 if (r.Sender != null) 210 return null; 211 r.Sender = value; 212 break; 213 case "destination": 214 if (r.Destination != null) 215 return null; 216 r.Destination = value; 217 break; 218 default: 219 if (Protocol.Verbose) 220 Console.Error.WriteLine ("Warning: Unrecognized match rule key: " + key); 221 break; 222 } 223 } 224 225 return r; 226 } 227 } 228 } 229