View Javadoc

1   /*
2    * Copyright  2004-2005 Stefan Reuter
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   *
16   */
17  package net.sf.asterisk.fastagi.impl;
18  
19  import java.io.Serializable;
20  import java.io.UnsupportedEncodingException;
21  import java.net.InetAddress;
22  import java.net.URLDecoder;
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.HashMap;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.StringTokenizer;
30  import java.util.regex.Matcher;
31  import java.util.regex.Pattern;
32  
33  import net.sf.asterisk.fastagi.AGIRequest;
34  import net.sf.asterisk.util.Log;
35  import net.sf.asterisk.util.LogFactory;
36  
37  /***
38   * Default implementation of the AGIRequest interface.
39   * 
40   * @author srt
41   * @version $Id: AGIRequestImpl.java,v 1.11 2005/11/27 16:08:17 srt Exp $
42   */
43  public class AGIRequestImpl implements Serializable, AGIRequest
44  {
45      private final Log logger = LogFactory.getLog(getClass());
46      private static final Pattern SCRIPT_PATTERN = Pattern
47              .compile("^([^//?]*)//?(.*)$");
48      private static final Pattern PARAMETER_PATTERN = Pattern
49              .compile("^(.*)=(.*)$");
50  
51      private String rawCallerId;
52  
53      /***
54       * Serial version identifier.
55       */
56      private static final long serialVersionUID = 3257001047145789496L;
57  
58      private Map request;
59  
60      /***
61       * A map assigning the values of a parameter (an array of Strings) to the
62       * name of the parameter.
63       */
64      private Map parameterMap;
65  
66      private String parameters;
67      private String script;
68      private boolean callerIdCreated;
69      private InetAddress localAddress;
70      private int localPort;
71      private InetAddress remoteAddress;
72      private int remotePort;
73  
74      /***
75       * Creates a new AGIRequestImpl.
76       * 
77       * @param environment the first lines as received from Asterisk containing
78       *            the environment.
79       */
80      public AGIRequestImpl(final Collection environment)
81      {
82          if (environment == null)
83          {
84              throw new IllegalArgumentException("Environment must not be null.");
85          }
86          request = buildMap(environment);
87      }
88  
89      /***
90       * Builds a map containing variable names as key (with the "agi_" prefix
91       * stripped) and the corresponding values.<br>
92       * Syntactically invalid and empty variables are skipped.
93       * 
94       * @param lines the environment to transform.
95       * @return a map with the variables set corresponding to the given
96       *         environment.
97       */
98      private Map buildMap(final Collection lines)
99      {
100         Map map;
101         Iterator lineIterator;
102 
103         map = new HashMap();
104         lineIterator = lines.iterator();
105 
106         while (lineIterator.hasNext())
107         {
108             String line;
109             int colonPosition;
110             String key;
111             String value;
112 
113             line = (String) lineIterator.next();
114             colonPosition = line.indexOf(':');
115 
116             // no colon on the line?
117             if (colonPosition < 0)
118             {
119                 continue;
120             }
121 
122             // key doesn't start with agi_?
123             if (!line.startsWith("agi_"))
124             {
125                 continue;
126             }
127 
128             // first colon in line is last character -> no value present?
129             if (line.length() < colonPosition + 2)
130             {
131                 continue;
132             }
133 
134             key = line.substring(4, colonPosition).toLowerCase();
135             value = line.substring(colonPosition + 2);
136 
137             if (value.length() != 0)
138             {
139                 map.put(key, value);
140             }
141         }
142 
143         return map;
144     }
145 
146     public Map getRequest()
147     {
148         return request;
149     }
150 
151     /***
152      * Returns the name of the script to execute.
153      * 
154      * @return the name of the script to execute.
155      */
156     public synchronized String getScript()
157     {
158         if (script != null)
159         {
160             return script;
161         }
162 
163         script = (String) request.get("network_script");
164         if (script != null)
165         {
166             Matcher scriptMatcher = SCRIPT_PATTERN.matcher(script);
167             if (scriptMatcher.matches())
168             {
169                 script = scriptMatcher.group(1);
170                 parameters = scriptMatcher.group(2);
171             }
172         }
173 
174         return script;
175     }
176 
177     /***
178      * Returns the full URL of the request in the form
179      * agi://host[:port][/script].
180      * 
181      * @return the full URL of the request in the form
182      *         agi://host[:port][/script].
183      */
184     public String getRequestURL()
185     {
186         return (String) request.get("request");
187     }
188 
189     /***
190      * Returns the name of the channel.
191      * 
192      * @return the name of the channel.
193      */
194     public String getChannel()
195     {
196         return (String) request.get("channel");
197     }
198 
199     /***
200      * Returns the unqiue id of the channel.
201      * 
202      * @return the unqiue id of the channel.
203      */
204     public String getUniqueId()
205     {
206         return (String) request.get("uniqueid");
207     }
208 
209     public String getType()
210     {
211         return (String) request.get("type");
212     }
213 
214     public String getLanguage()
215     {
216         return (String) request.get("language");
217     }
218 
219     public String getCallerId()
220     {
221         String callerIdName;
222         String callerId;
223 
224         callerIdName = (String) request.get("calleridname");
225         callerId = (String) request.get("callerid");
226         if (callerIdName != null)
227         {
228             // Asterisk 1.2
229             if (callerId == null || "unknown".equals(callerId))
230             {
231                 return null;
232             }
233 
234             return callerId;
235         }
236         else
237         {
238             // Asterisk 1.0
239             return getCallerId10();
240         }
241     }
242 
243     public String getCallerIdName()
244     {
245         String callerIdName;
246 
247         callerIdName = (String) request.get("calleridname");
248         if (callerIdName != null)
249         {
250             // Asterisk 1.2
251             if ("unknown".equals(callerIdName))
252             {
253                 return null;
254             }
255 
256             return callerIdName;
257         }
258         else
259         {
260             // Asterisk 1.0
261             return getCallerIdName10();
262         }
263     }
264 
265     /***
266      * Returns the Caller*ID using Asterisk 1.0 logic.
267      * 
268      * @return the Caller*ID
269      */
270     private String getCallerId10()
271     {
272         int lbPosition;
273         int rbPosition;
274 
275         if (!callerIdCreated)
276         {
277             rawCallerId = (String) request.get("callerid");
278             callerIdCreated = true;
279         }
280 
281         if (rawCallerId == null)
282         {
283             return null;
284         }
285 
286         lbPosition = rawCallerId.indexOf('<');
287         rbPosition = rawCallerId.indexOf('>');
288 
289         if (lbPosition < 0 || rbPosition < 0)
290         {
291             return rawCallerId;
292         }
293 
294         return rawCallerId.substring(lbPosition + 1, rbPosition);
295     }
296 
297     /***
298      * Returns the Caller*ID using Asterisk 1.0 logic.
299      * 
300      * @return the Caller*ID Name
301      */
302     private String getCallerIdName10()
303     {
304         int lbPosition;
305         String callerIdName;
306 
307         if (!callerIdCreated)
308         {
309             rawCallerId = (String) request.get("callerid");
310             callerIdCreated = true;
311         }
312 
313         if (rawCallerId == null)
314         {
315             return null;
316         }
317 
318         lbPosition = rawCallerId.indexOf('<');
319 
320         if (lbPosition < 0)
321         {
322             return null;
323         }
324 
325         callerIdName = rawCallerId.substring(0, lbPosition).trim();
326         if (callerIdName.startsWith("\"") && callerIdName.endsWith("\""))
327         {
328             callerIdName = callerIdName.substring(1, callerIdName.length() - 1);
329         }
330 
331         if (callerIdName.length() == 0)
332         {
333             return null;
334         }
335         else
336         {
337             return callerIdName;
338         }
339     }
340 
341     public String getDnid()
342     {
343         String dnid;
344         
345         dnid = (String) request.get("dnid");
346         
347         if (dnid == null || "unknown".equals(dnid))
348         {
349             return null;
350         }
351         
352         return dnid; 
353     }
354 
355     public String getRdnis()
356     {
357         String rdnis;
358         
359         rdnis = (String) request.get("rdnis");
360         
361         if (rdnis == null || "unknown".equals(rdnis))
362         {
363             return null;
364         }
365         
366         return rdnis; 
367     }
368 
369     public String getContext()
370     {
371         return (String) request.get("context");
372     }
373 
374     public String getExtension()
375     {
376         return (String) request.get("extension");
377     }
378 
379     public Integer getPriority()
380     {
381         if (request.get("priority") != null)
382         {
383             return new Integer((String) request.get("priority"));
384         }
385         return null;
386     }
387 
388     public Boolean getEnhanced()
389     {
390         if (request.get("enhanced") != null)
391         {
392             if ("1.0".equals((String) request.get("enhanced")))
393             {
394                 return Boolean.TRUE;
395             }
396             else
397             {
398                 return Boolean.FALSE;
399             }
400         }
401         return null;
402     }
403 
404     public String getAccountCode()
405     {
406         return (String) request.get("accountCode");
407     }
408 
409     public Integer getCallingAni2()
410     {
411         if (request.get("callingani2") == null)
412         {
413             return null;
414         }
415         
416         try
417         {
418             return Integer.valueOf((String) request.get("callingani2"));
419         }
420         catch (NumberFormatException e)
421         {
422             return null;
423         }
424     }
425 
426     public Integer getCallingPres()
427     {
428         if (request.get("callingpres") == null)
429         {
430             return null;
431         }
432         
433         try
434         {
435             return Integer.valueOf((String) request.get("callingpres"));
436         }
437         catch (NumberFormatException e)
438         {
439             return null;
440         }
441     }
442 
443     public Integer getCallingTns()
444     {
445         if (request.get("callingtns") == null)
446         {
447             return null;
448         }
449         
450         try
451         {
452             return Integer.valueOf((String) request.get("callingtns"));
453         }
454         catch (NumberFormatException e)
455         {
456             return null;
457         }
458     }
459 
460     public Integer getCallingTon()
461     {
462         if (request.get("callington") == null)
463         {
464             return null;
465         }
466         
467         try
468         {
469             return Integer.valueOf((String) request.get("callington"));
470         }
471         catch (NumberFormatException e)
472         {
473             return null;
474         }
475     }
476 
477     public String getParameter(String name)
478     {
479         String[] values;
480 
481         values = getParameterValues(name);
482 
483         if (values == null || values.length == 0)
484         {
485             return null;
486         }
487 
488         return values[0];
489     }
490 
491     public String[] getParameterValues(String name)
492     {
493         if (getParameterMap().isEmpty())
494         {
495             return null;
496         }
497 
498         return (String[]) parameterMap.get(name);
499     }
500 
501     public synchronized Map getParameterMap()
502     {
503         if (parameterMap == null)
504         {
505             parameterMap = parseParameters(parameters);
506         }
507         return parameterMap;
508     }
509 
510     /***
511      * Parses the given parameter string and caches the result.
512      * 
513      * @param s the parameter string to parse
514      * @return a Map made up of parameter names their values
515      */
516     private synchronized Map parseParameters(String s)
517     {
518         Map parameterMap;
519         Map result;
520         Iterator parameterIterator;
521         StringTokenizer st;
522 
523         parameterMap = new HashMap();
524         if (s == null)
525         {
526             return parameterMap;
527         }
528 
529         st = new StringTokenizer(s, "&");
530         while (st.hasMoreTokens())
531         {
532             String parameter;
533             Matcher parameterMatcher;
534             String name;
535             String value;
536             List values;
537 
538             parameter = st.nextToken();
539             parameterMatcher = PARAMETER_PATTERN.matcher(parameter);
540             if (parameterMatcher.matches())
541             {
542                 try
543                 {
544                     name = URLDecoder
545                             .decode(parameterMatcher.group(1), "UTF-8");
546                     value = URLDecoder.decode(parameterMatcher.group(2),
547                             "UTF-8");
548                 }
549                 catch (UnsupportedEncodingException e)
550                 {
551                     logger.error("Unable to decode parameter '" + parameter
552                             + "'", e);
553                     continue;
554                 }
555             }
556             else
557             {
558                 try
559                 {
560                     name = URLDecoder.decode(parameter, "UTF-8");
561                     value = "";
562                 }
563                 catch (UnsupportedEncodingException e)
564                 {
565                     logger.error("Unable to decode parameter '" + parameter
566                             + "'", e);
567                     continue;
568                 }
569             }
570 
571             if (parameterMap.get(name) == null)
572             {
573                 values = new ArrayList();
574                 values.add(value);
575                 parameterMap.put(name, values);
576             }
577             else
578             {
579                 values = (List) parameterMap.get(name);
580                 values.add(value);
581             }
582         }
583 
584         result = new HashMap();
585         parameterIterator = parameterMap.keySet().iterator();
586         while (parameterIterator.hasNext())
587         {
588             String name;
589             List values;
590             String[] valueArray;
591 
592             name = (String) parameterIterator.next();
593             values = (List) parameterMap.get(name);
594 
595             valueArray = new String[values.size()];
596             result.put(name, values.toArray(valueArray));
597         }
598 
599         return result;
600     }
601 
602     public InetAddress getLocalAddress()
603     {
604         return localAddress;
605     }
606 
607     public void setLocalAddress(InetAddress localAddress)
608     {
609         this.localAddress = localAddress;
610     }
611 
612     public int getLocalPort()
613     {
614         return localPort;
615     }
616 
617     public void setLocalPort(int localPort)
618     {
619         this.localPort = localPort;
620     }
621 
622     public InetAddress getRemoteAddress()
623     {
624         return remoteAddress;
625     }
626 
627     public void setRemoteAddress(InetAddress remoteAddress)
628     {
629         this.remoteAddress = remoteAddress;
630     }
631 
632     public int getRemotePort()
633     {
634         return remotePort;
635     }
636 
637     public void setRemotePort(int remotePort)
638     {
639         this.remotePort = remotePort;
640     }
641 
642     public String toString()
643     {
644         StringBuffer sb;
645 
646         sb = new StringBuffer(getClass().getName() + ": ");
647         sb.append("script='" + getScript() + "'; ");
648         sb.append("requestURL='" + getRequestURL() + "'; ");
649         sb.append("channel='" + getChannel() + "'; ");
650         sb.append("uniqueId='" + getUniqueId() + "'; ");
651         sb.append("type='" + getType() + "'; ");
652         sb.append("language='" + getLanguage() + "'; ");
653         sb.append("callerId='" + getCallerId() + "'; ");
654         sb.append("callerIdName='" + getCallerIdName() + "'; ");
655         sb.append("dnid='" + getDnid() + "'; ");
656         sb.append("rdnis='" + getRdnis() + "'; ");
657         sb.append("context='" + getContext() + "'; ");
658         sb.append("extension='" + getExtension() + "'; ");
659         sb.append("priority='" + getPriority() + "'; ");
660         sb.append("enhanced='" + getEnhanced() + "'; ");
661         sb.append("accountCode='" + getAccountCode() + "'; ");
662         sb.append("systemHashcode=" + System.identityHashCode(this));
663 
664         return sb.toString();
665     }
666 }