Softpanorama

May the source be with you, but remember the KISS principle ;-)
Home Switchboard Unix Administration Red Hat TCP/IP Networks Neoliberalism Toxic Managers
(slightly skeptical) Educational society promoting "Back to basics" movement against IT overcomplexity and  bastardization of classic Unix

Asterisk Dialplan Basics

Old News Asterisk The Open Source PBX
(main page)
Recommended Links Dialplan examples Reference Lua in asterisk
Dialplan Programming Extensions More Dialplan Concepts Simple menu programming Queue  
Users, Peers and Friends Asterisk variables Troubleshooting Festival Humor Etc

The dialplan defines how Asterisk handles inbound and outbound calls. It is specified in the configuration file named extensions.conf. The extensions.conf file usually resides in the /etc/asterisk/ directory.

The dialplan is made up of four main concepts:

If you installed the sample configuration files when you installed Asterisk, you will most likely have an existing extensions.conf file. Instead of starting with the sample file, we suggest that you build your extensions.conf file from scratch. This will be very beneficial, as it will give you a better understanding of dialplan concepts and fundamentals.

Sample extensions.conf is an important resource, with reusable examples and ideas. You need to save it for example as extensions.conf.sample. In case you lost it you can get it from the /configs/ directory of the Asterisk source.

Contexts

Dialplans are broken into sections called contexts. Contexts are named groups of extensions, which serve several purposes.

Contexts keep different parts of the dialplan from interacting with one another. An extension that is defined in one context is completely isolated from extensions in any other context, unless interaction is specifically allowed. (We'll cover how to allow interaction between contexts near the end of the chapter.)

As a simple example, let's imagine we have two companies sharing an Asterisk server. If we place each company's voice menu in its own context, they are effectively separated from each other. This allows us to independently define what happens when, say, extension 0 is dialed: people pressing 0 at Company A's voice menu will get Company A's receptionist, and callers pressing 0 at Company B's voice menu will get Company B's receptionist. (This example assumes, of course, that we've told Asterisk to transfer the calls to the receptionists when callers press 0.)

Contexts are denoted by placing the name of the context inside square brackets ([ ]). The name can be made up of the letters A through Z (upper- and lowercase), the numbers 0 through 9, and the hyphen and underscore.[*] For example, a context for incoming calls looks like this:

[*] Please note that the space is conspicuously absent from the list of allowed characters. Don't use spaces in your context names—you won't like the result!

[incoming]

NOTE

Context names have a maximum length of 79 characters (80 characters –1 terminating null)

 

All of the instructions placed after a context definition are part of that context, until the next context is defined.

At the beginning of the dialplan, there are two special contexts:

When you define a channel (which is how you connect things to the system), one of the parameters that is defined in the channel definition is the context. In other words, the context is the point in the dialplan where connections from that channel will begin.

Another important use of contexts (perhaps the most important) is to provide security. By using contexts correctly, you can give certain callers access to features (such as long-distance calling) that aren't made available to others. If you don't design your dialplan carefully, you may inadvertently allow others to fraudulently use your system. Please keep this in mind as you build your Asterisk system.

 

The doc/ subdirectory of the Asterisk source code contains a very important file named security.txt, which outlines several steps you should take to keep your Asterisk system secure. It is vitally important that you read and understand this file. If you ignore the security precautions outlined there, you may end up allowing anyone and everyone to make long-distance or toll calls at your expense!

If you don't take the security of your Asterisk system seriously, you may end up paying—literally! Please take the time and effort to secure your system from toll fraud.

 

Extensions

Extension is to a numeric identifier given to a line that rings a particular phone.

In Asterisk an extension defines a sequnce of steps (each step containing an application) that Asterisk will take that call through. Within each context, we can define as many extensions as required. When a particular extension is triggered (by an incoming call or by digits being dialed on a channel), Asterisk starts executing steps defined in  dialplan for that extension. It is the extensions, therefore, that specify what happens to calls as they make their way through the dialplan.

The syntax for an extension is the word exten, followed by an arrow formed by the equals sign and the greater-than sign, like this:

exten =>

This is followed by the name (or number) of the extension. When dealing with traditional telephone systems, we tend to think of extensions as the numbers you would dial to make another phone ring. In Asterisk, you get a whole lot more; for example, extension names can be any combination of numbers and letters. Over the course of this chapter and the next, we'll use both numeric and alphanumeric extensions.

 

Assigning names to extensions may seem like a revolutionary concept, but when you realize that many VoIP transports support (or even actively encourage) dialing by name or email address instead of only dialing by number, it makes perfect sense. This is one of the features that makes Asterisk so flexible and powerful.


 

A complete extension is composed of three components:

These three components are separated by commas, like this:

exten => name,priority,application()

Here's a simple example of what a real extension might look like:

exten => 123,1,Answer()

In this example, the extension name is 123, the priority is 1, and the application is Answer(). Now, let's move ahead and explain priorities and applications.

Priorities

The second parameter called priority is essentially a sequnctial number that increases by one for each step. In other words each priority is numbered sequentially, starting with 1. For example:

exten => 123,1,Answer()
exten => 123,2,Hangup()

Unnumbered priorities

Numbering priorrities sequntially is not very convininet and if you need to add a step between two priorities you need to renumber all of them.

Beginning with version 1.2, Asterisk addressed this problem. It introduced the use of the n priority, which stands for "next." Each time Asterisk encounters a priority named n, it takes the number of the previous priority and adds 1. This makes it easier to make changes to your dialplan, as you don't have to keep renumbering all your steps. For example, your dialplan might look something like this:

exten => 123,1,Answer()
exten => 123,n,do something
exten => 123,n,do something else
exten => 123,n,do one last thing
exten => 123,n,Hangup()

Internally, Asterisk will calculate the next priority number every time it encounters an n.[] You should note, however, that you must always specify priority number 1. If you accidentally put an n instead of 1 for the first priority, you'll find that the extension will not be available.

[] Asterisk permits simple arithmetic within the priority, such as n+200 or the priority s (for same), but their usage is considered to be an advanced topic. Please note that extension s and priority s are two distinct concepts.

Priority labels

Starting with Asterisk version 1.2 and higher, common practice is to assign text labels to priorities. This is to ensure that you can refer to a priority by something other than its number, which probably isn't known, given that dialplans now generally use unnumbered priorities. To assign a text label to a priority, simply add the label inside parentheses after the priority, like this:

exten => 123,n(label),application()
 

A very common mistake when writing labels is to insert a comma between the n and the (, like this:

exten => 123,n,(label),application() ;<-- THIS IS NOT GOING TO WORK

 

This mistake will break that part of your dialplan, and you will get an error that the application cannot be found.

 

In the next chapter, we'll cover how to jump between different priorities based on dialplan logic. You'll be seeing a lot more of priority labels, and you will be using them often in your dialplans.

Applications

Applications is the last field in definition of extension. Each application performs a specific action on the current channel, such as playing a sound, accepting touch-tone input, dialing a channel, hanging up the call, and so forth. In the previous example, you were introduced to two simple applications: Answer() and Hangup(). You'll learn more about how these work momentarily.

Some applications, such as Answer()and Hangup(), need no other instructions to do their jobs. Other applications require additional information. These pieces of information, called arguments, can be passed on to the applications to affect how they perform their actions. To pass arguments to an application, place them between the parentheses that follow the application name, separated by commas.

 

Occasionally, you may also see the pipe character (|) being used as a separator between arguments, instead of a comma. Feel free to use whichever you prefer. For the examples in this book, we will be using the comma to separate arguments to an application, as the authors prefer the look of this syntax. You should be aware, however, that when Asterisk parses the dialplan, it converts any commas in the application arguments to pipes.

 

As we build our first dialplan in the next section, you'll learn to use applications (and their associated arguments) to your advantage.

A Simple Dialplan

Now we're ready to create our first dialplan. We'll start with a very simple example. We are going to instruct Asterisk to answer a call, play a sound file, and hang up. We'll use this simple example to point out the most important dialplan fundamentals.

For the examples in this chapter to work correctly, we're assuming that at least one channel (either Zap, SIP, or IAX2) has been created and configured (as described in the previous chapter), and that all calls coming into that channel enter the dialplan at the [incoming] context. If you have been creative with any previous examples, you may need to make adjustments to fit your particular channel names.

The s Extension

Because of the technology we are using in our channels, we need to cover one more thing before we get started with our dialplan. We need to explain extension s. When calls enter a context without a specific destination extension (for example, a ringing FXO line), they are passed to the s extension. (The s stands for "start," as this is where a call will start if no extension information was passed with the call.)

Since this is exactly what we need for our dialplan, let's begin to fill in the pieces. We will be performing three actions on the call (answer it, play a sound file, and hang it up), so our extension called s will need three priorities. We'll place the three priorities below [incoming], because we have decided that all incoming calls should start in this context.[]

[] There is nothing special about any context name. We could have named this context [stuff_that_comes_in], and as long as that was the context assigned in the channel definition in sip.conf, iax.conf, zaptel.conf, et al., the channel would enter the dialplan in that context. Having said that, it is strongly recommended that you give your contexts names that help you to understand their purpose. Some good context names might include [incoming], [local_calls], [long_distance], [sip_telephones], [user_services], [experimental], [remote_locations], and so forth. Always remember that a context determines how a channel enters the dialplan, so name accordingly.

[incoming]
exten => s,1,application()
exten => s,n,application()
exten => s,n,application()

Now all we need to do is fill in the applications, and we've created our first dialplan.

NOTE

Note that we could have numbered each priority as shown below, but this is no longer the preferred method, as it makes it harder to make changes to the dialplan at a later time:

[incoming]
exten => s,1,application()
exten => s,2,application()
exten => s,3,application()

The Answer(), Playback(), and Hangup() Applications

If we're going to answer the call, play a sound file, and then hang up, we'd better learn how to do just that. The Answer() application is used to answer a channel that is ringing. This does the initial setup for the channel that receives the incoming call. (A few applications don't require that you answer the channel first, but properly answering the channel before performing any other actions is a very good habit.) As we mentioned earlier, Answer() takes no arguments.

The Playback() application is used for playing a previously recorded sound file over a channel. Asterisk comes with many professionally recorded sound files, which should be found in the default sounds directory (usually /var/lib/asterisk/sounds/). Several of the files in our examples come from the Extra Sound Package, so please take the time to install it. You can also have your own sound prompts recorded in the same voices as the stock prompts by visiting (http://thevoice.digium.com/).

When using the Playback() application, input from the user is simply ignored.

To use Playback(), specify a filename (without a file extension) as the argument. For example, Playback(filename) would play the sound file called filename.gsm, assuming it was located in the default sounds directory. You can also include the full path to the file, for example:

Playback(/home/john/sounds/filename)

The previous example would play filename.gsm from the /home/john/sounds/ directory. You can also use relative paths from the Asterisk sounds directory as follows:

Playback(custom/filename)

This example would play filename.gsm from the custom/ subdirectory of the default sounds directory (probably /var/lib/asterisk/sounds/custom/filename.gsm). Note that if the specified directory contains more than one file with that filename but with different file extensions, Asterisk automatically plays the best file.[§]

[§] Asterisk selects the best file based on translation costthat is, it selects the file that is the least CPU-intensive to convert to its native audio format. When you start Asterisk, it calculates the translation costs between the different audio formats (they often vary from system to system). You can see these translation costs by typing show translation at the Asterisk command-line interface. The numbers shown represent how many milliseconds it takes Asterisk to transcode one second of audio. We'll cover more about the different audio formats (known as codecs) in Chapter 8.

The Hangup() application does exactly as its name implies: it hangs up the active channel. You should use this application at the end of a context when you want to end the current call to ensure that callers don't continue on in the dialplan in a way you might not have anticipated. The Hangup() application takes no arguments.

 Our First Dialplan

Now that we have designed our extension, let's put together all the pieces to create our first dialplan. As is typical in many technology books (especially computer programming books), our first example will be called "Hello World!"

In the first priority of our extension, we'll answer the call. In the second, we'll play a sound file named hello-world.gsm, and in the third we'll hang up the call. Here's what the dialplan looks like:

[incoming]
exten => s,1,Answer()
exten => s,n,Playback(hello-world)
exten => s,n,Hangup()

If you have a channel or two configured, go ahead and try it out![||] Simply create a file called extensions.conf, (probably in /etc/asterisk) and insert the four lines of dialplan code we just designed. If it doesn't work, check the Asterisk console for error messages, and make sure your channels are assigned to the [incoming] context.

[||] In fact, if you don't have any channels configured, now is the time to do so. There is a real satisfaction that comes from passing your first call into an Asterisk system that you built from scratch. People get this funny grin on their face as they realize that they have just created a telephone system. This pleasure can be yours as well, so please, don't go any further until you have made this little dialplan work.

Even though this example is very short and simple, it emphasizes the core concepts of contexts, extensions, priorities, and applications. If you can get this to work, you have the fundamental knowledge on which all dialplans are built.

Let's build upon our example. After all, a phone system that simply plays a sound file and then hangs up the channel isn't that useful!

Building an Interactive Dialplan

The dialplan we just built was static; it will always perform the same actions on every call. We are going to start adding some logic to our dialplan so that it will perform different actions based on input from the user. To do this, we're going to need to introduce a few more applications.

The Background(), WaitExten(), and Goto() Applications

One of the most important keys to building interactive Asterisk dialplans is the Background()[#] application. Like Playback(), it plays a recorded sound file. Unlike Playback(), however, when the caller presses a key (or series of keys) on her telephone keypad, it interrupts the playback and goes to the extension that corresponds with the pressed digit(s). If a caller presses 5, for example, Asterisk will stop playing the sound prompt and send control of the call to the first priority of extension 5.

[#] It should be noted that some people expect that Background(), due to its name, would continue in the dialplan while the sound is being played, but its name refers to the fact that it is playing a sound in the background, while waiting for DTMF in the foreground.

The most common use of the Background() application is to create voice menus (often called auto-attendants or phone trees). Many companies use voice menus to direct callers to the proper extensions, thus relieving their receptionists from having to answer every single call.

Background() has the same syntax as Playback():

exten => 123,1,Answer()
exten => 123,n,Background(main-menu)

In earlier versions of Asterisk, if the Background() application finished playing the sound prompt and there were no more priorities in the current extension, Asterisk would sit and wait for input from the caller. Asterisk no longer does this by default. If you want Asterisk to wait for input from the caller after the sound prompt has finished playing, you can call the WaitExten() application. The WaitExten() application waits for the caller to enter DTMF digits, and is frequently called directly after the Background() application, like this:

exten => 123,1,Answer()
exten => 123,n,Background(main-menu)
exten => 123,n,WaitExten()

If you'd like the WaitExten() application to wait a specific number of seconds for a response (instead of using the default timeout), simply pass the number of seconds as the first argument to WaitExten(), like this:

exten => 123,n,WaitExten(5)

Both Background() and WaitExten() allow the caller to enter DTMF digits. Asterisk then attempts to find an extension in the current context that matches the digits that the caller entered. If Asterisk finds an unambiguous match, it will send the call to that extension. Let's demonstrate by adding a few lines to our example:

exten => 123,1,Answer()
exten => 123,n,Background(main-menu)
exten => 123,n,WaitExten()

exten => 2,1,Playback(digits/2)

exten => 3,1,Playback(digits/3)

exten => 4,1,Playback(digits/4)

If you call into extension 123 in the example above, it will play a sound prompt that says "main menu." It will then wait for you to enter either 2, 3, or 4. If you press one of those digits, Asterisk will read that digit back to you. You'll also find that if you enter a different digit (such as 5), it won't give you what you expected.

It is also possible that Asterisk will find an ambiguous match. This can be easily explained if we add an extension named 1 to the previous example:

exten => 123,1,Answer()
exten => 123,n,Background(main-menu)
exten => 123,n,WaitExten()

exten => 1,1,Playback(digits/1)

exten => 2,1,Playback(digits/2)

exten => 3,1,Playback(digits/3)

exten => 4,1,Playback(digits/4)

Dial extension 123, and then at the main menu prompt dial 1. Why doesn't Asterisk immediately read back the number one to you? It's because the digit 1 is ambiguous; Asterisk doesn't know whether you're trying to go to extension 1 or extension 123. It waits a few seconds to see if you're going to dial another digit (such as the 2 in extension 123). If you don't dial any more digits, Asterisk will eventually time out and send the call to extension 1. (We'll learn how to choose our own timeout values in Chapter 6.)

Before going on, let's revieow what we've done so far. When users call into our dialplan, they will hear a greeting. If they press 1, they will hear the number one, and if they press 2, they will hear the number two, and so on. While that's a good start, let's embellish it a little. We'll use the Goto() application to make the dialplan repeat the greeting after playing back the number.

As its name implies, the Goto() application is used to send the call to another part of the dialplan. The syntax for the Goto() application requires us to pass the destination context, extension, and priority on as arguments to the application, like this:

exten => 123,n,Goto(context,extension,priority)

Now, let's use the Goto() application in our dialplan:

[incoming]
exten => 123,1,Answer()
exten => 123,n,Background(main-menu)

exten => 1,1,Playback(digits/1)
exten => 1,n,Goto(incoming,123,1)

exten => 2,1,Playback(digits/2)
exten => 2,n,Goto(incoming,123,1)

These two new lines (highlighted in bold) will send control of the call back to the 123 extension after playing back the selected number.

 

 

If you look up the details of the Goto() application, you'll find that you can actually pass either one, two, or three arguments to the application. If you pass a single argument, Asterisk will assume it's the destination priority in the current extension. If you pass two arguments, Asterisk will treat them as the extension and priority to go to in the current context.

In this example, we've passed all three arguments for the sake of clarity, but passing just the extension and priority would have had the same effect.

 

Handling Invalid Entries and Timeouts

Now that our first voice menu is starting to come together, let's add some additional special extensions. First, we need an extension for invalid entries; when a caller presses an invalid entry (e.g., pressing 9 in the above example), the call is sent to the i extension. Second, we need an extension to handle situations when the caller doesn't give input in time (the default timeout is 10 seconds). Calls will be sent to the t extension if the caller takes too long to press a digit after WaitExten() has been called. Here is what our dialplan will look like after we've added these two extensions:

[incoming]
exten => 123,1,Answer()
exten => 123,n,Background(enter-ext-of-person)
exten => 123,n,WaitExten()

exten => 1,1,Playback(digits/1)
exten => 1,n,Goto(incoming,123,1)

exten => 2,1,Playback(digits/2)
exten => 2,n,Goto(incoming,123,1)

exten => 3,1,Playback(digits/3)
exten => 3,n,Goto(incoming,123,1)

exten => i,1,Playback(pbx-invalid)
exten => i,n,Goto(incoming,123,1)

exten => t,1,Playback(vm-goodbye)
exten => t,n,Hangup()

Using the i and t extensions makes our dialplan a little more robust and user-friendly. That being said, it is still quite limited, because outside callers have no way of connecting to a live person. To do that, we'll need to learn about another application, called Dial().

5.3.3. Using the Dial() Application

One of Asterisk's most valuable features is its ability to connect different callers to each other. This is especially useful when callers are using different methods of communication. For example, caller A might be communicating over the traditional analog telephone network, while user B might be sitting in a café halfway around the world and speaking on an IP telephone. Luckily, Asterisk takes most of the hard work out of connecting and translating between disparate networks. All you have to do is learn how to use the Dial() application.

The syntax of the Dial() application is a little more complex than that of the other applications we've used so far, but don't let that scare you off. Dial() takes up to four arguments. The first is the destination you're attempting to call, which (in its simplest form) is made up of a technology (or transport) across which to make the call, a forward slash, and the remote endpoint or resource. Common technology types include Zap (for analog and T1/E1/J1 channels), SIP, and IAX2. For example, let's assume that we want to call a Zap endpoint identified by Zap/1, which is an FXS channel with an analog phone plugged into it. The technology is Zap, and the resource is 1. Similarly, a call to a SIP device (as defined in sip.conf) might have a destination of SIP/Jane, and a call to an IAX device (defined in iax.conf) might have a destination of IAX2/Fred. If we wanted Asterisk to ring the Zap/1 channel when extension 123 is reached in the dialplan, we'd add the following extension:

exten => 123,1,Dial(Zap/1)

We can also dial multiple channels at the same time, by concatenating the destinations with an ampersand (&), like this:

exten => 123,1,Dial(Zap/1&Zap/2&SIP/Jane)

The Dial() application will ring the specified destinations simultaneously, and bridge the inbound call with whichever destination channel answers the call first. If the Dial() application can't contact any of the destinations, Asterisk will set a variable called DIALSTATUS with the reason that it couldn't dial the destinations, and continue on with the next priority in the extension.[**]

[**] Don't worry, we'll cover variables (in Section 5.3.5) and show you how to have your dialplan make decisions based on the value of this DIALSTATUS variable.

The Dial() application also allows you to connect to a remote VoIP endpoint not previously defined in one of the channel configuration files. The full syntax for this type of connection is:

Dial(technology/user[:password]@remote_host[:port][/remote_extension])

As an example, you can dial into a demonstration server at Digium using the IAX2 protocol by using the following extension:

exten => 500,1,Dial(IAX2/[email protected]/s)

The full syntax for the Dial() application is slightly different when dealing with Zap channels, as shown:

Dial(Zap/[gGrR]channel_or_group[/remote_extension])

For example, here is how you would dial 1-800-555-1212 on Zap channel number 4.

exten => 501,1,Dial(Zap/4/18005551212)

The second argument to the Dial() application is a timeout, specified in seconds. If a timeout is given, Dial() will attempt to call the destination(s) for that number of seconds before giving up and moving on to the next priority in the extension. If no timeout is specified, Dial() will continue to dial the called channel(s) until someone answers or the caller hangs up. Let's add a timeout of 10 seconds to our extension:

exten => 123,1,Dial(Zap/1,10)

If the call is answered before the timeout, the channels are bridged and the dialplan is done. If the destination simply does not answer, is busy, or is otherwise unavailable, Asterisk will set a variable called DIALSTATUS and then continue on with the next priority in the extension.

Let's put what we've learned so far into another example:

exten => 123,1,Dial(Zap/1,10)    
exten => 123,n,Playback(vm-nobodyavail)
exten => 123,n,Hangup()

As you can see, this example will play the vm-nobodyavail.gsm sound file if the call goes unanswered.

The third argument to Dial() is an option string. It may contain one or more characters that modify the behavior of the Dial() application. While the list of possible options is too long to cover here, one of the most popular options is the m option. If you place the letter m as the third argument, the calling party will hear hold music instead of ringing while the destination channel is being called (assuming, of course, that music on hold has been configured correctly). To add the m option to our last example, we simply change the first line:

exten => 123,1,Dial(Zap/1,10,m)
exten => 123,n,Playback(vm-nobodyavail)
exten => 123,n,Hangup()

Since the extensions numbered 1 and 2 in our dialplan are somewhat useless now that we know how to use the Dial() application, let's replace them with new extensions that will allow outside callers to reach John and Jane:

[incoming]
exten => 123,1,Answer()
exten => 123,n,Background(enter-ext-of-person)
exten => 123,n,WaitExten()

exten => 1,1,Dial(Zap/1,10)
exten => 1,n,Playback(vm-nobodyavail)
exten => 1,n,Hangup()

exten => 2,1,Dial(SIP/Jane,10)
exten => 2,n,Playback(vm-nobodyavail)
exten => 2,n,Hangup()

exten => i,1,Playback(pbx-invalid)
exten => i,n,Goto(incoming,123,1)

exten => t,1,Playback(vm-goodbye)
exten => t,n,Hangup()

The fourth and final argument to the Dial() application is a URL. If the destination channel supports receiving a URL at the time of the call, the specified URL will be sent (for example, if you have an IP telephone that supports receiving a URL, it will appear on the phone's display; likewise, if you're using a soft phone, the URL might pop up on your computer screen). This argument is very rarely used.

Note that the second, third, and fourth arguments may be left blank. For example, if you want to specify an option but not a timeout, simply leave the timeout argument blank, like this:

exten => 1,1,Dial(Zap/1,,m)

5.3.4. Adding a Context for Internal Calls

In our examples thus far, we have limited ourselves to a single context, but it is probably fair to assume that almost all Asterisk installations will have more than one context in their dialplans. As we mentioned at the beginning of this chapter, one important function of contexts is to separate privileges (such as making long-distance calls or calling certain extensions) for different classes of callers. In our next example, we'll add to our dialplan by creating two internal phone extensions, and we'll set up the ability for these two extensions to call each other. To accomplish this, we'll create a new context called [employees].

 

As in previous examples, we've assumed that an FXS analog channel (Zap/1, in this case) has already been configured, and that your zapata.conf file is configured so that any calls originated by Zap/1 begin in the [employees] context. For a few examples at the end of the chapter, we'll also assume that an FXO Zap channel has been configured as Zap/4, with calls coming in on this channel being sent to the [incoming] context.

We've also assumed you have at least one SIP channel (named SIP/Jane) that is configured to originate in the [employees] context. We've done this to introduce you to using other types of channels.

If you don't have hardware for the channels listed above (such as Zap/4), or if you're using hardware with different channel names (e.g., not SIP/Jane), just change the examples to match your particular system configuration.

 

Our dialplan now looks like this:

[incoming]
exten => 123,1,Answer()
exten => 123,n,Background(enter-ext-of-person)
exten => 123,n,WaitExten()

exten => 1,1,Dial(Zap/1,10)
exten => 1,n,Playback(vm-nobodyavail)
exten => 1,n,Hangup()

exten => 2,1,Dial(SIP/Jane,10)
exten => 2,n,Playback(vm-nobodyavail)
exten => 2,n,Hangup()

exten => i,1,Playback(pbx-invalid)
exten => i,n,Goto(incoming,123,1)

exten => t,1,Playback(vm-goodbye)
exten => t,n,Hangup()

[employees]
exten => 101,1,Dial(Zap/1)

exten => 102,1,Dial(SIP/Jane)

In this example, we have added two new extensions to the [employees] context. This way, the person using channel Zap/1 can pick up the phone and dial the person at channel SIP/Jane by dialing 102. By that same token, the phone registered as SIP/Jane can dial Zap/1 by dialing 101.

We've arbitrarily decided to use extensions 101 and 102 for our examples, but feel free to use whatever numbering convention you wish for your extensions. You should also be aware that you're not limited to three-digit extensions; you can use as few or as many digits as you like. (Well, almost. Extensions must be shorter than 80 characters long, and you shouldn't use single-character extensions for your own use, as they're reserved.) Don't forget that you can use names as well, like so:

[incoming]
exten => 123,1,Answer()
exten => 123,n,Background(enter-ext-of-person)
exten => 123,n,WaitExten()

exten => 1,1,Dial(Zap/1,10)
exten => 1,n,Playback(vm-nobodyavail)
exten => 1,n,Hangup()

exten => 2,1,Dial(SIP/Jane,10)
exten => 2,n,Playback(vm-nobodyavail)
exten => 2,n,Hangup()

exten => i,1,Playback(pbx-invalid)
exten => i,n,Goto(incoming,123,1)

exten => t,1,Playback(vm-goodbye)
exten => t,n,Hangup()

[employees]
exten => 101,1,Dial(Zap/1)
exten => john,1,Dial(Zap/1)

exten => 102,1,Dial(SIP/Jane)
exten => jane,1,Dial(SIP/Jane)

It certainly wouldn't hurt to add named extensions if you think your users might be dialed via a VoIP protocol such as SIP that supports dialing by name. You can also see that it is possible to have different extensions in the dialplan ring the same endpoint. For example, you could have extension 200 ring SIP/George, and then have extension 201 play a prompt of some kind and then ring SIP/George.

Now that our internal callers can call each other, we're well on our way toward having a complete dialplan. Next, we'll see how we can make our dialplan more scalable and easier to modify in the future.

5.3.5. Using Variables

Variables can be used in an Asterisk dialplan to help reduce typing, add clarity, or add additional logic to a dialplan. If you have some computer programming experience, you probably already understand what a variable is. If not, don't worry; we'll explain what variables are and how they are used.

You can think of a variable as a container that can hold one value at a time. So, for example, we might create a variable called JOHN and assign it the value of Zap/1. This way, when we're writing our dialplan, we can refer to John's channel by name, instead of remembering that John is using the channel named Zap/1.

There are two ways to reference a variable. To reference the variable's name, simply type the name of the variable, such as JOHN. If, on the other hand, you want to reference its value, you must type a dollar sign, an opening curly brace, the name of the variable, and a closing curly brace. Here's how we'd reference the variable inside the Dial() application:

exten => 555,1,Dial(${JOHN})

In our dialplan, whenever we write ${JOHN}, Asterisk will automatically replace it with whatever value has been assigned to the variable named JOHN.

 

 

Note that variable names are case-sensitive. A variable named JOHN is different than a variable named John. For readability's sake, all the variable names in the examples will be written in uppercase. You should also be aware that any variables set by Asterisk will be uppercase as well. Some variables, such as CHANNEL or EXTEN are reserved by Asterisk. You should not attempt to set these variables.

 

There are three types of variables we can use in our dialplan: global variables, channel variables, and environment variables. Let's take a moment to look at each type.

5.3.5.1. Global variables

As their name implies, global variables apply to all extensions in all contexts. Global variables are useful in that they can be used anywhere within a dialplan to increase readability and manageability. Suppose for a moment that you had a large dialplan and several hundred references to the Zap/1 channel. Now imagine you had to go through your dialplan and change all of those references to Zap/2. It would be a long and error-prone process, to say the least.

On the other hand, if you had defined a global variable with the value Zap/1 at the beginning of your dialplan and then referenced that instead, you would have to change only one line.

Global variables should be declared in the [globals] context at the beginning of the extensions.conf file. They can also be defined programmatically, using the GLOBAL() dialplan function.[] Here is an example of how both methods look inside of a dialplan. The first shows the setting of a global variable named JOHN with a value of Zap/1. This variable is set at the time Asterisk parses the dialplan. The second example shows how a global variable can be set in the dialplan. In this case, the variable named George is being assigned the value of SIP/George when extension 124 is dialed in the [employees]context:

[] Don't worry! We'll cover dialplan functions in the Section 6.2 section.

[globals]
JOHN=Zap/1

[employees]
exten => 124,1,Set(GLOBAL(GEORGE)=SIP/George)
5.3.5.2. Channel variables

A channel variable is a variable that is associated only with a particular call. Unlike global variables, channel variables are defined only for the duration of the current call and are available only to the channels participating in that call.

There are many predefined channel variables available for use within the dialplan, which are explained in the channelvariables.txt file in the doc subdirectory of the Asterisk source. Channel variables are set via the Set() application:

exten => 125,1,Set(MAGICNUMBER=42)

We'll cover many uses for channel variables in Chapter 6.

5.3.5.3. Environment variables

Environment variables are a way of accessing Unix environment variables from within Asterisk. These are referenced using the ENV() dialplan function. The syntax looks like ${ENV(var)}, where var is the Unix environment variable you wish to reference. Environment variables aren't commonly used in Asterisk dialplans, but they are available should you need them.

5.3.5.4. Adding variables to our dialplan

Now that we've learned about variables, let's put them to work in our dialplan. We'll add global variables for two people, John and Jane:

Code View: Scroll / Show All
[globals]
JOHN=Zap/1
JANE=SIP/Jane

[incoming]
exten => 123,1,Answer()
exten => 123,n,Background(enter-ext-of-person)
exten => 123,n,WaitExten()

exten => 1,1,Dial(${JOHN},10)
exten => 1,n,Playback(vm-nobodyavail)
exten => 1,n,Hangup()

exten => 2,1,Dial(${JANE},10)
exten => 2,n,Playback(vm-nobodyavail)
exten => 2,n,Hangup()

exten => i,1,Playback(pbx-invalid)
exten => i,n,Goto(incoming,123,1)

exten => t,1,Playback(vm-goodbye)
exten => t,n,Hangup()

[employees]

exten => 101,1,Dial(${JOHN})
exten => john,1,Dial(${JOHN})

exten => 102,1,Dial(${JANE})
exten => jane,1,Dial(${JANE})

Pattern Matching

Patten matching in Dialplan is the classic case of reinventing the bicycle. Asterisk designers probably never used Unix or AWK or Perl so they designed there own primitive pattern matching scheme,  Patterns always start with an underscore (_). This tells Asterisk that we're matching on a pattern, and not on an explicit extension name. (This means, of course, that you should never start your extension names with an underscore.)

 

If you forget the underscore on the front of your pattern, Asterisk will think it's just a named extension and won't do any pattern matching. This is one of the most common mistakes people make when starting to learn Asterisk.

 

After the underscore, you can use one or more of the following characters.

To use pattern matching in your dialplan, simply put the pattern in the place of the extension name (or number):

exten => _NXX,1,Playback(auth-thankyou)

In this example, the pattern matches any three-digit extension from 200 through 999 (the N matches any digit between 2 and 9, and each X matches a digit between 0 and 9). That is to say, if a caller dialed any three-digit extension between 200 and 999 in this context, he would hear the sound file auth-thankyou.gsm.

One other important thing to know about pattern matching is that if Asterisk finds more than one pattern that matches the dialed extension, it will use the most specific one (going from left to right). Say you had defined the following two patterns, and a caller dialed 555-1212:

exten => _555XXXX,1,Playback(digits/1)
exten => _55512XX,1,Playback(digits/2)

In this case the second extension would be selected, because it is more specific.

Pattern-matching examples

Before we go on, let's look at a few more pattern-matching examples. In each one, see if you can tell what the pattern would match before reading the explanation. We'll start with an easy one:

_NXXXXXX

This pattern would match any seven-digit number, as long as the first digit was two or higher. This pattern would be compatible with any North American Numbering Plan local seven-digit number. In areas with 10-digit dialing, that pattern would look like this:

_NXXNXXXXXX

Note that neither of these two patterns would handle long distance calls. We'll cover those shortly.

The North American Number Plan (NANP) is a shared telephone numbering scheme used by 19 countries in North America and the Caribbean. Countries within NANP share country code 1.

In the United States and Canada, telecom regulations are similar (and sensible) enough that you can place a long-distance call to most numbers in country code 1 and expect to pay a reasonable toll. What many people don't realize, however, is that 19 countries, many of which have very different telecom regulations, share the NANP. (More information can be found at (http://www.nanpa.com).)

One popular scam using the NANP tries to trick naive North Americans into calling expensive per-minute toll numbers in a Caribbean country; the callers believe that since they dialed 1-NPA-NXX-XXXX to reach the number, they'll be paying their standard national long-distance rate for the call. Since the country in question may have regulations that allow for this form of extortion, the caller is ultimately held responsible for the call charges.

The only way to prevent this sort of activity is to block calls to certain area codes (809, for example) and remove the restrictions only on an as-needed basis.

 

Let's try another:

_1NXXNXXXXXX

This one is slightly more difficult. This would match the number 1, followed by an area code between 200 and 999, then any 7-digit number. In the NANP calling area, you would use this pattern to match any long-distance number.

If you grew up in North America, you may believe that the 1 you dial before a long distance call is "the long distance code." This is incorrect. The number 1 is in fact the international country code for all countries in NANP. Keep this in mind if you ever send your phone number to someone in another country. They may not know what your country code is, and thus be unable to call you with just your area code and phone number. Your full phone number with country code should be printed as +1 NPA NXX XXXX (where NPA is your area code)e.g., +1 416 555 1212.

Now for an even trickier example:

_011.

If that one left you scratching your head, look at it again. Did you notice the period on the end? This pattern matches any number that starts with 011 and has at least one more digit. In the NANP, this indicates an international phone number. (We'll be using these patterns in the next section to add outbound dialing capabilities to our dialplan.)

Using the ${EXTEN} channel variable

We know what you're thinking… You're sitting there asking yourself, "So what happens if I want to use pattern matching, but I need to know which digits were actually dialed?" Luckily, Asterisk has just the answer. Whenever you dial an extension, Asterisk sets the ${EXTEN} channel variable to the digits that were dialed. We can use an application called SayDigits() to test it out:

exten => _XXX,1,SayDigits(${EXTEN})

In this example, the SayDigits() application will read back to you the three-digit extension you dialed.

Often, it's useful to manipulate the ${EXTEN} by stripping a certain number of digits off the front of the extension. This is accomplished by using the syntax ${EXTEN:x}, where x is where you want the returned string to start, from left to right. For example, if the value of EXTEN is 95551212, ${EXTEN:1} equals 5551212. Let's take a look at another example:

exten => _XXX,1,SayDigits(${EXTEN:1})

In this example, the SayDigits() application would start at the second digit, and thus read back only the last two digits of the dialed extension.

 

The ${EXTEN} variable properly has the syntax ${EXTEN:x:y}, where x is the starting position, and y is the number of digits to return. Given the following dial string:

94169671111

we can extract the following digit strings using the ${EXTEN:x:y} construct:

${EXTEN:1:3} would contain 416.

${EXTEN:4:7} would contain 9671111.

${EXTEN:-4:4} would start four digits from the end, and return four digits, giving us 1111.

${EXTEN:1} would give us everything after the first digit, 4169671111 (if the number of digits to return is left blank, it will return the entire remaining string).

This is a very powerful construct, but most of these variations are not very common in normal use. For the most part, you will be using ${EXTEN:1} to strip off your external access code.

 

Enabling Outbound Dialing

Now that we've introduced pattern matching, we can go about the process of allowing users to make outbound calls. The first thing we'll do is add a variable to the [globals] context to define which channel will be used for outbound calls:

[globals]
JOHN=Zap/1
JANE=SIP/Jane
OUTBOUNDTRUNK=Zap/4

Next, we will add contexts to our dialplan for outbound dialing.

You may be asking yourself at this point, "Why do we need separate contexts for outbound calls?" This is so that we can regulate and control which callers have permission to make outbound calls, and which types of outbound calls they are allowed to make.

To begin, let's create a context for local calls. To be consistent with most traditional phone switches, we'll put a 9 on the front of our patterns, so that users have to dial 9 before calling an outside number:

[outbound-local]
exten => _9NXXXXXX,1,Dial(${OUTBOUNDTRUNK}/${EXTEN:1})
exten => _9NXXXXXX,n,Congestion()
exten => _9NXXXXXX,n,Hangup()

 

 

Note that dialing 9 doesn't actually give you an outside line, unlike with many traditional PBX systems. Once you dial 9 on an analog line, the dial tone will stop. If you'd like the dial tone to continue even after dialing 9, add the following line (right after your context definition):

ignorepat => 9

 

This directive tells Asterisk to continue to provide a dial tone on an analog line, even after the caller has dialed the indicated pattern. This will not work with VoIP telephones, as they usually don't send digits to the system as they are input; they are sent to Asterisk all at once. Luckily, most of the popular VoIP telephones can be configured to emulate the same functionality.

Let's review what we've just done. We've added a global variable called OUTBOUNDTRUNK, which simply defines the channel we are using for outbound calls.[§§] We've also added a context for local outbound calls. In priority 1, we take the dialed extension, strip off the 9 with the ${EXTEN:1} syntax, and then attempt to dial that number on the channel signified by the variable OUTBOUNDTRUNK. If the call is successful, the caller is bridged with the outbound channel. If the call is unsuccessful (because either the channel is busy or the number can't be dialed for some reason), the Congestion() application is called, which plays a "fast busy signal" (congestion tone) to let the caller know that the call was unsuccessful.

[§§] The advantage of this is that if one day we decide to send all of our calls through some other channel, we have to edit the channel name assigned to the variable OUTBOUNDTRUNK only in the [globals] context, instead of having to manually edit every reference to the channel in our dialplan.

Before we go any further, let's make sure our dialplan allows outbound emergency numbers:

[outbound-local]
exten => _9NXXXXXX,1,Dial(${OUTBOUNDTRUNK}/${EXTEN:1})
exten => _9NXXXXXX,n,Congestion()
exten => _9NXXXXXX,n,Hangup()

exten => 911,1,Dial(${OUTBOUNDTRUNK}/911)
exten => 9911,1,Dial(${OUTBOUNDTRUNK}/911) ; So that folks who dial "9" 
                                           ; first will also get through

Again, we're assuming for the sake of these examples that we're inside the United States or Canada. If you're outside of this area, please replace 911 with the emergency services number in your particular location. This is something you never want to forget to put in your dialplan!

Next, let's add a context for long-distance calls:

[outbound-long-distance]
exten => _91NXXNXXXXXX,1,Dial(${OUTBOUNDTRUNK}/${EXTEN:1})
exten => _91NXXNXXXXXX,n,Playtones(congestion)
exten => _91NXXNXXXXXX,n,Hangup()

Now that we have these two new contexts, how do we allow internal users to take advantage of them? We need a way for contexts to be able to use the functionality contained in other contexts.

Includes

Asterisk has a feature that enables us to use the extensions from one context within another context via the include directive. This is used to control access to different sections of the dialplan. We'll use the include functionality to allow users in our [employees] context the ability to make outbound phone calls. But first, let's cover the syntax.

The include statement takes the following form, where context is the name of the remote context we want to include in the current context:

include => context

When we include other contexts within our current context, we have to be mindful of the order in which we are including them. Asterisk will first try to match the dialed extension in the current context. If unsuccessful, it will then try the first included context (including any contexts included in that context), and then continue to the other included contexts in the order in which they were included.

As it sits, our current dialplan has two contexts for outbound calls, but there's no way for people in the [employees] context to use them. Let's remedy that by including the two outbound contexts in the [employees] context, like this:

Code View: Scroll / Show All
[globals]
JOHN=Zap/1
JANE=SIP/Jane
OUTBOUNDTRUNK=Zap/4

[incoming]
exten => 123,1,Answer()
exten => 123,n,Background(enter-ext-of-person)
exten => 123,n,WaitExten()

exten => 1,1,Dial(${JOHN},10)
exten => 1,n,Playback(vm-nobodyavail)
exten => 1,n,Hangup()

exten => 2,1,Dial(${JANE},10)
exten => 2,n,Playback(vm-nobodyavail)
exten => 2,n,Hangup()

exten => i,1,Playback(pbx-invalid)
exten => i,n,Goto(incoming,123,1)

exten => t,1,Playback(vm-goodbye)
exten => t,n,Hangup()

[employees]
include => outbound-local
include => outbound-long-distance

exten => 101,1,Dial(${JOHN})
exten => john,1,Dial(${JOHN})
exten => 102,1,Dial(${JANE})
exten => jane,1,Dial(${JANE})

[outbound-local]
exten => _9NXXXXXX,1,Dial(${OUTBOUNDTRUNK}/${EXTEN:1})
exten => _9NXXXXXX,n,Congestion()
exten => _9NXXXXXX,n,Hangup()

exten => 911,1,Dial(${OUTBOUNDTRUNK}/911)
exten => 9911,1,Dial(${OUTBOUNDTRUNK}/911)

[outbound-long-distance]
exten => _91NXXNXXXXXX,1,Dial(${OUTBOUNDTRUNK}/${EXTEN:1})
exten => _91NXXNXXXXXX,n,Playtones(congestion)
exten => _91NXXNXXXXXX,n,Hangup()

					 

These two include statements make it possible for callers in the [employees] context to make outbound calls. We should also note that for security's sake you should always make sure that your [inbound] context never allows outbound dialing. (If by chance it did, people could dial into your system and then make outbound toll calls that would be charged to you!)

All of these commands ultimately shut down Asterisk. If you make a configuration change that doesn't require a complete restart, like a change to a certain phone extension, you can just use reload at the Asterisk prompt.

Make Asterisk Answer Automatically

Now, save sip.conf and open up /etc/asterisk/extensions.conf. This file tells Asterisk what to do whenever a user dials a phone number. It contains the "dial plan" that guides the system-wide call-handling functionality of the Asterisk server. In the [default] section of the file, comment everything out and add these lines:

	exten => s,1,Answer
	exten => s,2,Playback(abandon-all-hope)
	exten => s,3,Hangup

Save the file and launch (or relaunch) Asterisk:

	# asterisk -rx reload

Now, calling the phone number of the line connected to the media gateway will result in the call being answered by the Asterisk server. You'll hear a voice message, and then the call will be hung up.

 

NEWS CONTENTS

Old News

[Jan 10, 2010] An interesting idea of jumping from menu to extension -- regular expression extension after WaitExten

exten => s,1,Answer()
exten => s,n,Background(hello-world)
exten => s,n,WaitExten()

exten => _20[0-9],1,Set(TARGETNO=${EXTEN})
exten => _20[0-9],n,Dial(SIP/${EXTEN},30)
exten => _20[0-9],n,VoiceMail(${EXTEN},b)
exten => _20[0-9],n,Hangup()

[Jan 16, 2009] Adding gateway

For stripping digits ( 9.,3,Dial(sip/${EXTEN:1}@vega,60,rtT) ) see Asterisk variables - voip-info.org

Using 9 to get to gateway (extentions.conf)

;
exten => _9.,1,Answer()
exten => _9.,2,Wait(1)
exten => _9.,3,Dial(sip/${EXTEN:1}@gateway,60,rtT)
exten => _9.,4,Busy()
exten => _9.,4,Congestion()
exten => _9.,4,Hangup()

sip.conf

;
[vega]
type=friend
context=test
qualify=yes
canreinvite=yes
insecure=very
host=10.192.190.13
disallow=all
allow=g729
allow=gsm
allow=ulaw



Etc

Society

Groupthink : Two Party System as Polyarchy : Corruption of Regulators : Bureaucracies : Understanding Micromanagers and Control Freaks : Toxic Managers :   Harvard Mafia : Diplomatic Communication : Surviving a Bad Performance Review : Insufficient Retirement Funds as Immanent Problem of Neoliberal Regime : PseudoScience : Who Rules America : Neoliberalism  : The Iron Law of Oligarchy : Libertarian Philosophy

Quotes

War and Peace : Skeptical Finance : John Kenneth Galbraith :Talleyrand : Oscar Wilde : Otto Von Bismarck : Keynes : George Carlin : Skeptics : Propaganda  : SE quotes : Language Design and Programming Quotes : Random IT-related quotesSomerset Maugham : Marcus Aurelius : Kurt Vonnegut : Eric Hoffer : Winston Churchill : Napoleon Bonaparte : Ambrose BierceBernard Shaw : Mark Twain Quotes

Bulletin:

Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient markets hypothesis : Political Skeptic Bulletin, 2013 : Unemployment Bulletin, 2010 :  Vol 23, No.10 (October, 2011) An observation about corporate security departments : Slightly Skeptical Euromaydan Chronicles, June 2014 : Greenspan legacy bulletin, 2008 : Vol 25, No.10 (October, 2013) Cryptolocker Trojan (Win32/Crilock.A) : Vol 25, No.08 (August, 2013) Cloud providers as intelligence collection hubs : Financial Humor Bulletin, 2010 : Inequality Bulletin, 2009 : Financial Humor Bulletin, 2008 : Copyleft Problems Bulletin, 2004 : Financial Humor Bulletin, 2011 : Energy Bulletin, 2010 : Malware Protection Bulletin, 2010 : Vol 26, No.1 (January, 2013) Object-Oriented Cult : Political Skeptic Bulletin, 2011 : Vol 23, No.11 (November, 2011) Softpanorama classification of sysadmin horror stories : Vol 25, No.05 (May, 2013) Corporate bullshit as a communication method  : Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law

History:

Fifty glorious years (1950-2000): the triumph of the US computer engineering : Donald Knuth : TAoCP and its Influence of Computer Science : Richard Stallman : Linus Torvalds  : Larry Wall  : John K. Ousterhout : CTSS : Multix OS Unix History : Unix shell history : VI editor : History of pipes concept : Solaris : MS DOSProgramming Languages History : PL/1 : Simula 67 : C : History of GCC developmentScripting Languages : Perl history   : OS History : Mail : DNS : SSH : CPU Instruction Sets : SPARC systems 1987-2006 : Norton Commander : Norton Utilities : Norton Ghost : Frontpage history : Malware Defense History : GNU Screen : OSS early history

Classic books:

The Peter Principle : Parkinson Law : 1984 : The Mythical Man-MonthHow to Solve It by George Polya : The Art of Computer Programming : The Elements of Programming Style : The Unix Hater’s Handbook : The Jargon file : The True Believer : Programming Pearls : The Good Soldier Svejk : The Power Elite

Most popular humor pages:

Manifest of the Softpanorama IT Slacker Society : Ten Commandments of the IT Slackers Society : Computer Humor Collection : BSD Logo Story : The Cuckoo's Egg : IT Slang : C++ Humor : ARE YOU A BBS ADDICT? : The Perl Purity Test : Object oriented programmers of all nations : Financial Humor : Financial Humor Bulletin, 2008 : Financial Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related Humor : Programming Language Humor : Goldman Sachs related humor : Greenspan humor : C Humor : Scripting Humor : Real Programmers Humor : Web Humor : GPL-related Humor : OFM Humor : Politically Incorrect Humor : IDS Humor : "Linux Sucks" Humor : Russian Musical Humor : Best Russian Programmer Humor : Microsoft plans to buy Catholic Church : Richard Stallman Related Humor : Admin Humor : Perl-related Humor : Linus Torvalds Related humor : PseudoScience Related Humor : Networking Humor : Shell Humor : Financial Humor Bulletin, 2011 : Financial Humor Bulletin, 2012 : Financial Humor Bulletin, 2013 : Java Humor : Software Engineering Humor : Sun Solaris Related Humor : Education Humor : IBM Humor : Assembler-related Humor : VIM Humor : Computer Viruses Humor : Bright tomorrow is rescheduled to a day after tomorrow : Classic Computer Humor

The Last but not Least Technology is dominated by two types of people: those who understand what they do not manage and those who manage what they do not understand ~Archibald Putt. Ph.D


Copyright © 1996-2021 by Softpanorama Society. www.softpanorama.org was initially created as a service to the (now defunct) UN Sustainable Development Networking Programme (SDNP) without any remuneration. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License. Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.

FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available to advance understanding of computer science, IT technology, economic, scientific, and social issues. We believe this constitutes a 'fair use' of any such copyrighted material as provided by section 107 of the US Copyright Law according to which such material can be distributed without profit exclusively for research and educational purposes.

This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Grammar and spelling errors should be expected. The site contain some broken links as it develops like a living tree...

You can use PayPal to to buy a cup of coffee for authors of this site

Disclaimer:

The statements, views and opinions presented on this web page are those of the author (or referenced source) and are not endorsed by, nor do they necessarily reflect, the opinions of the Softpanorama society. We do not warrant the correctness of the information provided or its fitness for any purpose. The site uses AdSense so you need to be aware of Google privacy policy. You you do not want to be tracked by Google please disable Javascript for this site. This site is perfectly usable without Javascript.

Last modified: March 12, 2019