Yes 4G + Asterisk + FreePBX = VoIP heaven

Short how-to to have Asterisk handle Yes 4G - both as outgoing trunk and incoming. Tested under CentOS 5.7, Asterisk 1.8.7.0.

You will need access to Yes Life iOS app (or any IP traffic analyzer if you are using Yes Life for Windows), and know how to build Asterisk from source.

1. Figure out your Yes authorization name and SIP server. Your Yes ID is different from your Yes authorization name. To find out your authorization, launch Yes Life for iOS. Go to "More" tab and tap on "System Log". Swipe the "ON" button to turn on Yes Life logging.

2. Still within Yes Life for iOS, sign-out and then sign-in again (you must reenter your password again). 

3. Go back to "System Log" in Yes Life for iOS, and send the log to yourself.

4. Check your email and open the log file. Search for line with this string: "Authorization: Digest username=". Your Yes authorization ID should be displayed in that line. For example, if my Yes ID is kambingbusuk@yes.my, my Yes authorization ID is kambingbusuk_ht1@yes.my. Notice the additional "ht1" after your username. The additional "ht1" part after your username is not fixed, hence the need to peruse the iOS log file.

5. To find your SIP server, search for this string: "Starting async DNS A query: target=". Mine is proxy11.yes.my.

6. Yes is using IMS Softswitch which use the "tel:" as URI to initiate and terminate calls. Asterisk SIP module only recognized "sip:" as the URI, so we need to modify the SIP code in Asterisk to support this. You can download the modified chan_sip.so and move it to /usr/lib64/asterisk/modules/ or apply this patch from your Asterisk source root path (tested against Asterisk 1.8.7.0):

--- channels/chan_sip.c.orig    2011-11-29 15:42:42.084207482 +0800
+++ channels/chan_sip.c 2011-11-28 22:26:18.596774409 +0800
@@ -5528,6 +5528,7 @@
                        ast_channel_queue_connected_line_update(ast, &connected, &update_connected);
                }
 
+               ast_log(LOG_WARNING, "uri: %s\n", uri);
                xmitres = transmit_invite(p, SIP_INVITE, 1, 2, uri);
                sip_pvt_unlock(p);
                if (xmitres == XMIT_ERROR)
@@ -9725,6 +9726,9 @@
                h = uri;
                if (!strncasecmp(h, "sip:", 4)) {
                        h += 4;
+               }
+               else if (!strncasecmp(h, "tel:", 4)) {
+                       h += 4;
                } else if (!strncasecmp(h, "sips:", 5)) {
                        h += 5;
                        tls_on = TRUE;
@@ -12267,7 +12271,7 @@
 
        ast_copy_string(from, get_header(&p->initreq, "From"), sizeof(from));
        c = get_in_brackets(from);
-       if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5)) {
+       if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5) && strncasecmp(c, "tel:", 4)) {
                ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", c);
                return -1;
        }
@@ -12276,7 +12280,7 @@
 
        ast_copy_string(to, get_header(&p->initreq, "To"), sizeof(to));
        c = get_in_brackets(to);
-       if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5)) {
+       if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5) && strncasecmp(c, "tel:", 4)) {
                ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", c);
                return -1;
        }
@@ -12999,6 +13003,9 @@
        ast_string_field_set(p, from, of);
        if (!strncasecmp(of, "sip:", 4)) {
                of += 4;
+       }
+       else if (!strncasecmp(of, "tel:", 4)) {
+               of += 4;
        } else if (!strncasecmp(of, "sips:", 5)) {
                of += 5;
                use_tls = TRUE;
@@ -13402,7 +13409,7 @@
         * We still need to be able to send to the remote agent through the proxy.
         */
 
-       if (parse_uri_legacy_check(contact, "sip:,sips:", &contact, NULL, &domain,
+       if (parse_uri_legacy_check(contact, "sip:,tel:,sips:", &contact, NULL, &domain,
                      &transport)) {
                ast_log(LOG_WARNING, "Invalid contact uri %s (missing sip: or sips:), attempting to use anyway\n", fullcontact);
        }
@@ -13538,7 +13545,7 @@
        ast_string_field_build(pvt, our_contact, "<%s>", curi);
 
        /* Make sure it's a SIP URL */
-       if (parse_uri_legacy_check(curi, "sip:,sips:", &curi, NULL, &domain, &transport)) {
+       if (parse_uri_legacy_check(curi, "sip:,tel:,sips:", &curi, NULL, &domain, &transport)) {
                ast_log(LOG_NOTICE, "Not a valid SIP contact (missing sip:/sips:) trying to use anyway\n");
        }
 
@@ -14232,7 +14239,7 @@
        c = get_in_brackets(tmp);
        c = remove_uri_parameters(c);
 
-       if (parse_uri_legacy_check(c, "sip:,sips:", &name, &dummy, &domain, NULL)) {
+       if (parse_uri_legacy_check(c, "sip:,tel:,sips:", &name, &dummy, &domain, NULL)) {
                ast_log(LOG_NOTICE, "Invalid to address: '%s' from %s (missing sip:) trying to use anyway...\n", c, ast_sockaddr_stringify_addr(addr));
                return -1;
        }
@@ -14716,6 +14723,9 @@
        exten = get_in_brackets(tmp);
        if (!strncasecmp(exten, "sip:", 4)) {
                exten += 4;
+       }
+       else if (!strncasecmp(exten, "tel:", 4)) {
+               exten += 4;
        } else if (!strncasecmp(exten, "sips:", 5)) {
                exten += 5;
        } else {
@@ -14813,7 +14823,7 @@
        
        uri = ast_strdupa(get_in_brackets(tmp));
 
-       if (parse_uri_legacy_check(uri, "sip:,sips:", &uri, &dummy, &domain, NULL)) {
+       if (parse_uri_legacy_check(uri, "sip:,tel:,sips:", &uri, &dummy, &domain, NULL)) {
                ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", uri);
                return SIP_GET_DEST_INVALID_URI;
        }
@@ -14838,7 +14848,7 @@
        ast_copy_string(tmpf, get_header(req, "From"), sizeof(tmpf));
        if (!ast_strlen_zero(tmpf)) {
                from = get_in_brackets(tmpf);
-               if (parse_uri_legacy_check(from, "sip:,sips:", &from, NULL, &domain, NULL)) {
+               if (parse_uri_legacy_check(from, "sip:,tel:,sips:", &from, NULL, &domain, NULL)) {
                        ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", from);
                        return SIP_GET_DEST_INVALID_URI;
                }
@@ -15058,6 +15068,9 @@
        refer_to = get_in_brackets(h_refer_to);
        if (!strncasecmp(refer_to, "sip:", 4)) {
                refer_to += 4;                  /* Skip sip: */
+       }
+       else if (!strncasecmp(refer_to, "tel:", 4)) {
+               refer_to += 4;                  /* Skip sip: */
        } else if (!strncasecmp(refer_to, "sips:", 5)) {
                refer_to += 5;
        } else {
@@ -15091,6 +15104,9 @@
 
                if (!strncasecmp(referred_by_uri, "sip:", 4)) {
                        referred_by_uri += 4;           /* Skip sip: */
+               }
+               else if (!strncasecmp(referred_by_uri, "tel:", 4)) {
+                       referred_by_uri += 4;           /* Skip sip: */
                } else if (!strncasecmp(referred_by_uri, "sips:", 5)) {
                        referred_by_uri += 5;           /* Skip sips: */
                } else {
@@ -15249,7 +15265,7 @@
        ast_copy_string(tmp, get_header(req, "Also"), sizeof(tmp));
        c = get_in_brackets(tmp);
 
-       if (parse_uri_legacy_check(c, "sip:,sips:", &c, NULL, &a, NULL)) {
+       if (parse_uri_legacy_check(c, "sip:,tel:,sips:", &c, NULL, &a, NULL)) {
                ast_log(LOG_WARNING, "Huh?  Not a SIP header in Also: transfer (%s)?\n", c);
                return -1;
        }
@@ -15601,6 +15617,8 @@
                char *t = uri2;
                if (!strncasecmp(t, "sip:", 4))
                        t+= 4;
+               else if (!strncasecmp(t, "tel:", 4))
+                       t+= 4;
                else if (!strncasecmp(t, "sips:", 5))
                        t += 5;
                ast_string_field_set(p, exten, t);
@@ -15618,7 +15636,7 @@
        ast_string_field_set(p, from, of);
 
        /* ignore all fields but name */
-       if (parse_uri_legacy_check(of, "sip:,sips:", &of, &dummy, &domain, NULL)) {
+       if (parse_uri_legacy_check(of, "sip:,tel:,sips:", &of, &dummy, &domain, NULL)) {
                ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
        }
 
@@ -19139,6 +19157,8 @@
 
                if (!strncasecmp(contact_number, "sip:", 4))
                        contact_number += 4;
+               else if (!strncasecmp(contact_number, "tel:", 4))
+                       contact_number += 4;
                else if (!strncasecmp(contact_number, "sips:", 5))
                        contact_number += 5;
                separator = strchr(contact_number, ';');        /* And username ; parameters? */
@@ -28700,7 +28720,7 @@
                        ast_log(LOG_ERROR, "Cannot retrieve the 'To' header from the original SIP request!\n");
                        return 0;
                }
-               if (((local_to_header = strcasestr(to_header, "sip:")) || (local_to_header = strcasestr(to_header, "sips:")))
+               if (((local_to_header = strcasestr(to_header, "sip:")) || (local_to_header = strcasestr(to_header, "sips:")) || (local_to_header = strcasestr(to_header, "tel:")))
                        && (local_to_header = strchr(local_to_header, '@'))) {
                        char ldomain[256];
 

7. Now build and install Asterisk as usual.
 
8. I'm using FreePBX as Asterisk front-end. Next we need to add for trunk for Yes. Open FreePBX admin, goto Setup -> Trunks. Add a SIP trunk. Fill in based on the following (assuming my Yes ID is kambingbusuk, Yes authorization is kambungbusuk_ht1, Yes number is 0187552525, Yes server / proxy is proxy11.yes.my):
 
General Settings:
Trunk name: Yes
Outbound Caller ID: <kambingbusuk>
 
Dialed Number Manipulation Rules:
Prepend: +6     Match pattern: 0ZXXXXXXX
Prepend: +6     Match pattern: 0ZXXXXXXXX
Prepend: +6     Match pattern: 0ZXXXXXXXXX
Prepend: +6     Match pattern: 0ZXXXXXX
Match pattern: +.
 
Outgoing Settings:
Trunk Name: kambingbusuk
PEER Details:
host=proxy11.yes.my
secret=mypasswordobviously
type=peer
qualify=no
insecure=very
dtmfmode=rfc2833
trustrpid=no
sendrpid=no
canreinvite=no
disallow=all
allow=alaw&ulaw&g729&ilbc&g722
fromuser=kambingbusuk
fromdomain=yes.my
usereqphone=yes
 
Incoming Settings:
USER Context: 0187552525
USER Details:
secret=mypasswordobviously
canreinvite=no
faxdetect=yes
context=from-trunk
insecure=very
qualify=no
type=user
disallow=all
allow=alaw&ulaw&g729&ilbc&g722
 
Registration:
Register String: kambingbusuk@yes.my:mypasswordobviously:kambingbusuk_ht1@yes.my@proxy11.yes.my/0187552525
 
9. Configure your outbound route to use this trunk, and you are done. Yes allow multiple incoming and outgoing stream, so you'll never hear the busy tone again!