smsc_cimd.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:39k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*****************************************************************************
  2. * smsc_cimd.c - Nokia SMS Center (CIMD 1.3).
  3. * Mikael Gueck for WapIT Ltd.
  4. */
  5. #include <errno.h>
  6. #include <string.h>
  7. #include <stdio.h>
  8. #include <unistd.h>
  9. #include <stdlib.h>
  10. #include <time.h>
  11. #include <sys/time.h>
  12. #include <sys/types.h>
  13. #include <sys/socket.h>
  14. #include "smsc.h"
  15. #include "smsc_p.h"
  16. #include "gwlib/gwlib.h"
  17. #include "alt_charsets.h"
  18. /******************************************************************************
  19. * Static functions
  20. */
  21. /* do the handshake baby */
  22. static int cimd_open_connection(SMSCenter *smsc);
  23. /* waits for an ACK message, returns the ACK command number or -1 for error */
  24. static int expect_acknowledge(SMSCenter *smsc, int *cmd, int *err);
  25. /* sends a general ACK */
  26. static int send_acknowledge(SMSCenter *smsc);
  27. /* Reconnect to a CIMD server, use an existing structure */
  28. static int connect_tcpip(SMSCenter *smsc);
  29. static int parse_cimd_to_iso88591(char *from, char *to, int length);
  30. static int parse_iso88591_to_cimd(
  31.     char *from, char *to, int length, int alt_charset);
  32. /******************************************************************************
  33. * Open the connection and log in
  34. *
  35. * return 0 if ok, -1 on failure
  36. */
  37. static int cimd_open_connection(SMSCenter *smsc)
  38. {
  39.     char *tmpbuff = NULL;
  40.     int ret = 0;
  41.     int cmd = 0, err = 0;
  42.     /* allocate some spare space */
  43.     tmpbuff = gw_malloc(10 * 1024);
  44.     memset(tmpbuff, 0, 10*1024);
  45.     /* connect */
  46.     smsc->socket = tcpip_connect_to_server(smsc->cimd_hostname, smsc->cimd_port,
  47. NULL);
  48. /* XXX add interface_name if required */
  49.     if (smsc->socket == -1)
  50.         goto error;
  51.     /* receive protocol string "CIMD rel 1.37n" */
  52.     for (;;) {
  53.         ret = smscenter_read_into_buffer(smsc);
  54.         if (strstr(smsc->buffer, "CIMD rel 1.37n") != NULL)
  55.             break;
  56.         if (ret < 0) goto logout;
  57.     }
  58.     debug("bb.sms.cimd", 0, "got the server identification tag");
  59.     smscenter_remove_from_buffer(smsc, smsc->buflen);
  60.     /* send login string */
  61.     sprintf(tmpbuff, "%c%s%c%s%c%s%c%s%c%c",
  62.             0x02,
  63.             "01", 0x09,
  64.             smsc->cimd_username, 0x09,
  65.             smsc->cimd_password, 0x09,
  66.             "11",
  67.             0x03, 0x0A);
  68.     ret = write_to_socket(smsc->socket, tmpbuff);
  69.     if (ret < 0) goto logout;
  70.     /* get an acknowledge message */
  71.     smsc->cimd_last_spoke = 0;
  72.     if (expect_acknowledge(smsc, &cmd, &err) < 1)
  73.         goto logout;
  74.     debug("bb.sms.cimd", 0, "logged in");
  75.     gw_free(tmpbuff);
  76.     return 0;
  77. logout:
  78.     cimd_close(smsc);
  79. error:
  80.     error(0, "cimd_open: could not open/handshake");
  81.     gw_free(tmpbuff);
  82.     return -1;
  83. }
  84. /******************************************************************************
  85. * Open the smscenter
  86. */
  87. SMSCenter *cimd_open(char *hostname, int port, char *username, char *password)
  88. {
  89.     SMSCenter *smsc = NULL;
  90.     int ret = 0;
  91.     /* create a SMSCenter structure */
  92.     smsc = smscenter_construct();
  93.     if (smsc == NULL) goto error;
  94.     smsc->type = SMSC_TYPE_CIMD;
  95.     smsc->cimd_hostname = gw_strdup(hostname);
  96.     smsc->hostname = gw_strdup(hostname); /* Needed by read_into_buffer() */
  97.     smsc->cimd_port = port;
  98.     smsc->cimd_username = gw_strdup(username);
  99.     smsc->cimd_password = gw_strdup(password);
  100.     ret = cimd_open_connection(smsc);
  101.     if (ret < 0)
  102.         goto error;
  103.     sprintf(smsc->name, "CIMD:%s:%d:%s", smsc->cimd_hostname,
  104.             smsc->cimd_port, smsc->cimd_username);
  105.     return smsc;
  106. error:
  107.     error(0, "cimd_open: could not open!");
  108.     smscenter_destruct(smsc);
  109.     return NULL;
  110. }
  111. /******************************************************************************
  112. * Re-open the connection and log in
  113. *
  114. * return -1 if failed
  115. */
  116. int cimd_reopen(SMSCenter *smsc)
  117. {
  118.     cimd_close(smsc);
  119.     if (cimd_open_connection(smsc) < 0) {
  120.         error(0, "Failed to re-open the connection!");
  121.         return -1;
  122.     }
  123.     return 0;
  124. }
  125. /******************************************************************************
  126. * Log out and close the socket
  127. *
  128. */
  129. int cimd_close(SMSCenter *smsc)
  130. {
  131.     char *cbuff = NULL;
  132.     int sum;
  133.     int ret;
  134.     if (smsc->socket == -1) {
  135.         debug("bb.sms.cimd", 0, "Trying to close cimd while already closed!");
  136.         return 0;
  137.     }
  138.     cbuff = gw_malloc(2 * 1024);
  139.     sprintf(cbuff, "%c%s%c%s%c%c", 0x02, "02", 0x09, "11", 0x03, 0x0A);
  140.     sum = write_to_socket(smsc->socket, cbuff);
  141.     if (sum < 0) goto error;
  142.     /* this time we don't block waiting for acknowledge */
  143.     recv(smsc->socket, cbuff, 2*1024, 0);
  144.     gw_free(cbuff);
  145.     ret = close(smsc->socket);
  146.     smsc->socket = -1;
  147.     return ret;
  148. error:
  149.     gw_free(cbuff);
  150.     return -1;
  151. }
  152. /******************************************************************************
  153. * Check for MO messages, returns as in smsc_submit_smsmessage in smsc.h
  154. */
  155. int cimd_pending_smsmessage(SMSCenter *smsc)
  156. {
  157.     char *tmpbuff = NULL, *newline = NULL;
  158.     int ret = 0;
  159.     time_t thetime = 0;
  160.     /* check for input sanity */
  161.     if (smsc == NULL)
  162.         goto error;
  163.     /* we can only query every 5 seconds */
  164.     thetime = time(NULL);
  165.     if ((smsc->cimd_last_spoke + 5) > thetime) goto no_messages;
  166.     smsc->cimd_last_spoke = thetime;
  167.     /* allocate some spare space */
  168.     tmpbuff = gw_malloc(10 * 1024);
  169.     memset(tmpbuff, 0, 10*1024);
  170.     sprintf(tmpbuff, "%c%s%c%s%c%c",
  171.             0x02,         /* stx */
  172.             "05", 0x09,   /* request for message, tab */
  173.             "11",         /* dummy chksum */
  174.             0x03, 0x0A);  /* etx, lf */
  175.     /* send the poll message to determine if we have messages in queue */
  176.     ret = write_to_socket(smsc->socket, tmpbuff);
  177.     if (ret < 0) {
  178.         debug("bb.sms.cimd", 0, "sending poll message failed");
  179.         goto error;
  180.     }
  181.     /* block while waiting for answer that dataset ends to a 0x0A */
  182.     for (;;) {
  183.         newline = memchr(smsc->buffer, 0x0A, smsc->buflen);
  184.         if (newline != NULL) break;
  185.         newline = memchr(smsc->buffer, 0x03, smsc->buflen);
  186.         if (newline != NULL) break;
  187.         ret = smscenter_read_into_buffer(smsc);
  188.         if (ret <= 0) {
  189.             debug("bb.sms.cimd", 0, "read_into_buffer failed!, ret=%d", ret);
  190.             goto error;
  191.         }
  192.         usleep(500);
  193.         /* Reconnect if no results in 30 seconds */
  194.         if (time(NULL) > (thetime + 30)) {
  195.             error(0, "timeout occurred, maybe the connection was broken?");
  196.             /* Reconnect if neccessary, this catches most of them */
  197.             /* XXX this is an ugly kludge, but then again,
  198.                CIMD 1.3 is an ugly kludge. */
  199.             connect_tcpip(smsc);
  200.             goto no_messages;
  201.         }
  202.     }
  203.     /* if we got an nck, cut the message out and return 0 */
  204.     newline = memchr(smsc->buffer, 0x15, smsc->buflen);
  205.     if (newline != NULL) {
  206.         newline = memchr(smsc->buffer, 0x0A, smsc->buflen);
  207.         if (newline == NULL)
  208.             newline = memchr(smsc->buffer, 0x03, smsc->buflen);
  209.         smscenter_remove_from_buffer(smsc, newline - smsc->buffer + 1);
  210.         goto no_messages;
  211.     }
  212.     /* miracle of miracles, we got a message */
  213.     gw_free(tmpbuff);
  214.     return 1;
  215. no_messages:
  216.     gw_free(tmpbuff);
  217.     return 0;
  218. error:
  219.     debug("bb.sms.cimd", 0, "smscenter_pending_smsmessage: returning error");
  220.     gw_free(tmpbuff);
  221.     return -1;
  222. }
  223. /******************************************************************************
  224. * Send a MT message, returns as in smsc_submit_smsmessage in smsc.h
  225. */
  226. int cimd_submit_msg(SMSCenter *smsc, Msg *msg)
  227. {
  228.     char *tmpbuff = NULL, *tmptext = NULL;
  229.     char msgtext[1024];
  230.     int ret;
  231.     int cmd = 0, err = 0;
  232.     /* Fix these by implementing a could-not-send-because-
  233.        protocol-does-not-allow in smsc.c or smsgateway.c */
  234.     if (octstr_len(msg->sms.msgdata) + octstr_len(msg->sms.udhdata) < 1) {
  235. if (msg->sms.msgdata == NULL)
  236.     msg->sms.msgdata = octstr_create("");
  237. octstr_append_from_hex(msg->sms.msgdata, "20");
  238.     }
  239.     if (octstr_len(msg->sms.sender) < 1) {
  240.         warning(0, "cimd_submit_smsmessage: ignoring message with 0-length field");
  241.         goto okay;  /* THIS IS NOT OKAY!!!! XXX */
  242.     }
  243.     if (octstr_len(msg->sms.receiver) < 1) {
  244.         warning(0, "cimd_submit_smsmessage: ignoring message with 0-length field");
  245.         goto okay;  /* THIS IS NOT OKAY!!!! XXX */
  246.     }
  247.     tmpbuff = gw_malloc(10 * 1024);
  248.     tmptext = gw_malloc(10 * 1024);
  249.     memset(tmpbuff, 0, 10*1024);
  250.     memset(tmptext, 0, 10*1024);
  251.     memset(msgtext, 0, sizeof(msgtext));
  252.     if (octstr_len(msg->sms.udhdata)) {
  253.         octstr_get_many_chars(msgtext, msg->sms.udhdata, 0, octstr_len(msg->sms.udhdata));
  254.         octstr_get_many_chars(msgtext + octstr_len(msg->sms.udhdata),
  255.                               msg->sms.msgdata, 0,
  256.                               140 - octstr_len(msg->sms.udhdata));
  257.     } else {
  258.         octstr_get_many_chars(msgtext, msg->sms.msgdata, 0,
  259.                               octstr_len(msg->sms.msgdata));
  260.     }
  261.     /* XXX parse_iso88591_to_cimd should use Octstr
  262.      * directly, or get a char* and a length, instead of using NUL
  263.      * terminated strings.
  264.      */
  265.     parse_iso88591_to_cimd(msgtext, tmptext, 10*1024, smsc->alt_charset);
  266.     /* If messages has UDHs, add the magic number 31 to the right spot */
  267.     sprintf(tmpbuff, "%c%s%c%s%c%s%c%s%c%s%c%s%c%s%c%c",
  268.             0x02,
  269.             "03", 0x09,
  270.             octstr_get_cstr(msg->sms.receiver), 0x09,
  271.             tmptext, 0x09,
  272.             "", 0x09,
  273.             "", 0x09,
  274.             (octstr_len(msg->sms.udhdata)) ? "31" : "", 0x09,
  275.             "11", 0x03, 0x0A);
  276.     ret = write_to_socket(smsc->socket, tmpbuff);
  277.     if (ret < 0) {
  278.         debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: socket write error");
  279.         goto error;
  280.     }
  281.     /* The Nokia SMSC MAY be configured to send delivery
  282.        information, which we then will HAVE to acknowledge.
  283.        Naturally the CIMD 1.3 protocol does not include any
  284.        kind of negotiation mechanism. */
  285.     ret = expect_acknowledge(smsc, &cmd, &err);
  286.     if (ret >= 1) {
  287.         if (cmd == 4) {
  288.             send_acknowledge(smsc);
  289.             goto okay;
  290.         } else if (cmd == 3) {
  291.             goto okay;
  292.         }
  293.     } else if (ret == 0) {
  294.         if (cmd == 4) {
  295.             send_acknowledge(smsc);
  296.             goto okay;  /* FIXME XXX THIS IS BOGUS, FIX SMSGATEWAY.C */
  297.             goto error;
  298.         } else if (cmd == 3) {
  299.             goto okay;  /* FIXME XXX THIS IS BOGUS, FIX SMSGATEWAY.C */
  300.             goto error;
  301.         } else {
  302.             error(0, "Unexpected behaviour from the CIMD server");
  303.             debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: acknowledge was <%i>", ret);
  304.             debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: buffer==<%s>", smsc->buffer);
  305.             goto error;
  306.         }
  307.     }
  308. okay:
  309.     gw_free(tmpbuff);
  310.     gw_free(tmptext);
  311.     return 0;
  312. error:
  313.     debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: returning error");
  314.     gw_free(tmpbuff);
  315.     gw_free(tmptext);
  316.     return -1;
  317. }
  318. int cimd_receive_msg(SMSCenter *smsc, Msg **msg)
  319. {
  320.     char *tmpbuff = NULL, *sender = NULL;
  321.     char *receiver = NULL, *text = NULL, *scts = NULL;
  322.     char *tmpchar = NULL;
  323.     debug("bb.sms.cimd", 0, "cimd_receive_smsmessage: starting");
  324.     /* the PENDING function has previously requested for
  325.        the message and checked that it safely found its 
  326.        way into the memory buffer (smsc->buffer) */
  327.     /* we want to temporarily store some data */
  328.     tmpbuff = gw_malloc(10 * 1024);
  329.     sender = gw_malloc(10 * 1024);
  330.     receiver = gw_malloc(10 * 1024);
  331.     text = gw_malloc(10 * 1024);
  332.     scts = gw_malloc(10 * 1024);
  333.     memset(tmpbuff, 0, 10 * 1024);
  334.     memset(sender, 0, 10 * 1024);
  335.     memset(receiver, 0, 10 * 1024);
  336.     memset(text, 0, 10 * 1024);
  337.     memset(scts, 0, 10 * 1024);
  338.     /* cut the raw message out from the message buffer */
  339.     tmpchar = memchr(smsc->buffer, 0x0A, smsc->buflen);
  340.     if (tmpchar == NULL) {
  341.         tmpchar = memchr(smsc->buffer, 0x03, smsc->buflen);
  342.         if (tmpchar == NULL) goto error;
  343.     }
  344.     strncpy(tmpbuff, smsc->buffer, tmpchar - smsc->buffer);
  345.     smscenter_remove_from_buffer(smsc, tmpchar - smsc->buffer + 1);
  346.     /* Parse the raw message */
  347.     sscanf(tmpbuff,
  348.            "x02x06tC:05t%[^t]t%[^t]t%[^t]t%[^t]t11x03x0A",
  349.            receiver, sender, text, scts);
  350.     sscanf(tmpbuff,
  351.            "x02x06tC:05t%[^t]t%[^t]t%[^t]t%[^t]t11x03",
  352.            receiver, sender, text, scts);
  353.     /* Translate from the CIMD character set to iso8859-1 */
  354.     parse_cimd_to_iso88591(text, tmpbuff, 10*1024);
  355.     strncpy(text, tmpbuff, 480);
  356.     /* create a smsmessage structure out of the components */
  357.     *msg = msg_create(sms);
  358.     if (*msg == NULL) return -1;
  359.     (*msg)->sms.sender = octstr_create(sender);
  360.     (*msg)->sms.receiver = octstr_create(receiver);
  361.     (*msg)->sms.msgdata = octstr_create(text);
  362.     /* Send acknowledge */
  363.     send_acknowledge(smsc);
  364.     /* We got a message so we can instantly check for a new one. */
  365.     smsc->cimd_last_spoke -= 5;
  366.     /* Free and Finish */
  367.     gw_free(tmpbuff);
  368.     gw_free(sender);
  369.     gw_free(receiver);
  370.     gw_free(text);
  371.     gw_free(scts);
  372.     debug("bb.sms.cimd", 0, "cimd_receive_smsmessage: return ok");
  373.     return 1;
  374. error:
  375.     debug("bb.sms.cimd", 0, "cimd_receive_smsmessage: failed");
  376.     gw_free(tmpbuff);
  377.     gw_free(sender);
  378.     gw_free(receiver);
  379.     gw_free(text);
  380.     gw_free(scts);
  381.     debug("bb.sms.cimd", 0, "cimd_receive_smsmessage: return failed");
  382.     return -1;
  383. }
  384. /******************************************************************************
  385. * In(f)ternal Functions
  386. */
  387. static int connect_tcpip(SMSCenter *smsc)
  388. {
  389.     char *tmpbuff = NULL;
  390.     int ret = 0;
  391.     int cmd = 0, err = 0;
  392.     debug("bb.sms.cimd", 0, "reconnecting to <%s>", smsc->name);
  393.     /* allocate some spare space */
  394.     tmpbuff = gw_malloc(10 * 1024);
  395.     memset(tmpbuff, 0, 10*1024);
  396.     /* Close connection */
  397.     close(smsc->socket);
  398.     smsc->socket = -1;
  399.     /* Be sure to open a socket. */
  400.     for (;;) {
  401.         smsc->socket = tcpip_connect_to_server(
  402.                            smsc->cimd_hostname, smsc->cimd_port,
  403.    NULL);
  404.     /* XXX add interface_name if required */
  405.         if (smsc->socket != -1) break;
  406.         usleep(1000);
  407.     }
  408.     /* Empty the buffer, there might be an evil ghost inside... */
  409.     memset(smsc->buffer, 0, smsc->bufsize);
  410.     smsc->buflen = 0;
  411.     /* Expect the protocol string "CIMD rel 1.37n" */
  412.     for (;;) {
  413.         ret = smscenter_read_into_buffer(smsc);
  414.         if (ret < 0) goto logout;
  415.         if (strstr(smsc->buffer, "CIMD rel 1.37n") != NULL)
  416.             break;
  417.         usleep(1000);
  418.     }
  419.     smscenter_remove_from_buffer(smsc, smsc->buflen);
  420.     /* send login string */
  421.     sprintf(tmpbuff, "%c%s%c%s%c%s%c%s%c%c",
  422.             0x02,
  423.             "01", 0x09,
  424.             smsc->cimd_username, 0x09,
  425.             smsc->cimd_password, 0x09,
  426.             "11",
  427.             0x03, 0x0A);
  428.     ret = write_to_socket(smsc->socket, tmpbuff);
  429.     if (ret < 0) goto logout;
  430.     /* get an acknowledge message */
  431.     smsc->cimd_last_spoke = 0;
  432.     if (expect_acknowledge(smsc, &cmd, &err) < 1)
  433.         goto logout;
  434.     debug("bb.sms.cimd", 0, "cimd_connect_tcpip: logged in");
  435.     gw_free(tmpbuff);
  436.     return 1;
  437. logout:
  438.     close(smsc->socket);
  439.     gw_free(tmpbuff);
  440.     return 0;
  441. }
  442. /******************************************************************************
  443. * Yeah, we got the message!
  444. */
  445. static int send_acknowledge(SMSCenter *smsc)
  446. {
  447.     char tmpbuff[100];
  448.     int tmpint;
  449.     if (tmpbuff == NULL) {
  450.         error(0, "cimd_send_acknowledge: memory allocation failure");
  451.         goto error;
  452.     }
  453.     memset(tmpbuff, 0, sizeof(tmpbuff));
  454.     sprintf(tmpbuff, "26t113n");
  455.     tmpint = write_to_socket(smsc->socket, tmpbuff);
  456.     if (tmpint == -1) {
  457.         error(0, "cimd_send_acknowledge: connection failure");
  458.         goto error;
  459.     }
  460.     return 0;
  461. error:
  462.     debug("bb.sms.cimd", 0, "cimd_send_acknowledge: failed");
  463.     return -1;
  464. }
  465. /******************************************************************************
  466. * Wait for the Nokia piece of *!%&%*^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H SMSC
  467. * to catch up with our swift operation, block until... (~1sec?)
  468. */
  469. static int expect_acknowledge(SMSCenter *smsc, int *cmd, int *err)
  470. {
  471.     char *end_of_dataset = NULL;
  472.     char *ack = NULL, *nck = NULL;
  473.     char *cmdspecifier = NULL, *errorspecifier = NULL;
  474.     int ret = 0;
  475. #if 0
  476.     time_t thetime;
  477.     time(&thetime);
  478. #endif
  479.     if (smsc == NULL) goto error;
  480.     /* Loop until we get an acknowledgement message. */
  481.     for (;;) {
  482.         /* If the server is configured in to end a dataset with a n */
  483.         end_of_dataset = memchr(smsc->buffer, 'n', smsc->buflen);
  484.         if (end_of_dataset != NULL) break;
  485.         /* If the server is configured in to end a dataset with a 3 */
  486.         end_of_dataset = memchr(smsc->buffer, 0x03, smsc->buflen);
  487.         if (end_of_dataset != NULL) break;
  488.         ret = smscenter_read_into_buffer(smsc);
  489.         if (ret <= 0) {
  490.             if (errno == EAGAIN) continue;
  491.             if (errno == EINTR) continue;
  492.             return -1;
  493.         }
  494.         usleep(500);
  495. #if 0
  496.         /* Abort if no results in 30 seconds */
  497.         if (time(NULL) > (thetime + 30)) {
  498.             error(0, "timeout occurred, maybe the connection was broken?");
  499.             if (errno == EPIPE) {
  500.                 error(0, "broken pipe");
  501.             } /* if errno */
  502.             goto error;
  503.         } /* if time */
  504. #endif
  505.     }
  506.     /* Check if our request was answered or denied */
  507.     ack = memchr(smsc->buffer, 0x06, end_of_dataset - smsc->buffer);
  508.     nck = memchr(smsc->buffer, 0x15, end_of_dataset - smsc->buffer);
  509.     /* Get the command code from the acknowledge message */
  510.     cmdspecifier = strstr(smsc->buffer, "tC:");
  511.     if (cmdspecifier != NULL)
  512.         *cmd = strtol(cmdspecifier + 3, NULL, 10);
  513.     else
  514.         *cmd = 0;
  515.     errorspecifier = strstr(smsc->buffer, "tE:");
  516.     if (errorspecifier != NULL)
  517.         *err = strtol(errorspecifier + 3, NULL, 10);
  518.     else
  519.         *err = 0;
  520.     debug("bb.sms.cimd", 0, "cimd_pending_smsmessage: smsc->buffer == <%s>", smsc->buffer);
  521.     /* Remove the acknowledge message from the incoming buffer. */
  522.     smscenter_remove_from_buffer(smsc, end_of_dataset - smsc->buffer + 1);
  523.     /* if we got an acknowledge */
  524.     if (ack != NULL) {
  525.         info(0, "cimd_pending_smsmessage: got ACK");
  526.         return 1;
  527.     }
  528.     /* if we got an NOT acknowledge */
  529.     if (nck != NULL) {
  530.         info(0, "cimd_pending_smsmessage: got NCK");
  531.         return 0;
  532.     }
  533.     /* if we got an ERROR */
  534. error:
  535.     error(0, "cimd_expect_acknowledge failed");
  536.     return -1;
  537. }
  538. /******************************************************************************
  539. * Convert a string from ISO-8859-1 to the CIMD character set
  540. */
  541. static int parse_iso88591_to_cimd(char* from, char* to,
  542.         int length, int alt_charset)
  543. {
  544.     char *temp = to;
  545.     if (from == NULL || to == NULL || length == 0)
  546.         return -1;
  547.     *to = '';
  548.     while ((*from != '') && ((int) strlen(temp) < (length - 2))) {
  549.         switch (*from) {
  550.         case '@': strcat(to, "_Oa"); to += 3; break;
  551.         case '