Example #1
0
/**
 * @name action_send_messages:
 */
int action_send_messages(gammu_state_t **sp,
                         int argc, char *argv[]) {

  int rv = 0;
  char **argp = &argv[1];

  if (argc <= 2) {
    print_usage_error(U_ERR_ARGS_MISSING);
    return 1;
  }

  if (argc % 2 != 1) {
    print_usage_error(U_ERR_ARGS_ODD);
    return 2;
  }

  /* Lazy initialization of libgammu */
  gammu_state_t *s = gammu_create_if_necessary(sp);

  if (!s) {
    print_operation_error(OP_ERR_INIT);
    rv = 3; goto cleanup;
  }

  /* Allocate */
  smsc_t *smsc = allocate(sizeof(*smsc));
  multimessage_t *sms = allocate(sizeof(*sms));
  multimessage_info_t *info = allocate(sizeof(*info));

  /* Find SMSC number */
  smsc->Location = 1;

  if ((s->err = GSM_GetSMSC(s->sm, smsc)) != ERR_NONE) {
    print_operation_error(OP_ERR_SMSC);
    rv = 4; goto cleanup_sms;
  }

  transmit_status_t status;
  initialize_transmit_status(&status);

  GSM_SetSendSMSStatusCallback(
    s->sm, _message_transmit_callback, &status
  );

  boolean_t is_start = TRUE;
  unsigned int message_index = 0;

  printf("[");

  /* For each message... */
  while (*argp != NULL) {

    GSM_ClearMultiPartSMSInfo(info);
    GSM_Debug_Info *debug = GSM_GetGlobalDebug();

    /* Copy/convert destination phone number */
    char *sms_destination_number = convert_utf8_utf16be(*argp++, FALSE);

    if (!sms_destination_number) {
      status.err = "Invalid UTF-8 sequence in destination number";
      goto cleanup_end;
    }

    string_info_t nsi;
    utf16be_string_info(sms_destination_number, &nsi);

    /* Check size of phone number:
        We'll be decoding this in to a fixed-sized buffer. */

    if (nsi.units >= GSM_MAX_NUMBER_LENGTH) {
      status.err = "Phone number is too long";
      goto cleanup_transmit_status;
    }

    /* Missing message text:
        This shouldn't happen since we check `argc` above,
        but I'm leaving this here in case we refactor later. */

    if (*argp == NULL) {
      status.err = "No message body provided";
      goto cleanup_transmit_status;
    }

    /* UTF-8 message content */
    char *sms_message = *argp++;

    /* Convert message from UTF-8 to UTF-16-BE:
        Every symbol is two bytes long; the string is then
        terminated by a single 2-byte UTF-16 null character. */

    char *sms_message_utf16be = convert_utf8_utf16be(sms_message, FALSE);

    if (!sms_message_utf16be) {
      status.err = "Invalid UTF-8 sequence";
      goto cleanup_transmit_status;
    }

    /* Prepare message info structure:
        This information is used to encode the possibly-multipart SMS. */

    info->Class = 1;
    info->EntriesNum = 1;
    info->Entries[0].ID = SMS_ConcatenatedTextLong;
    info->Entries[0].Buffer = (uint8_t *) sms_message_utf16be;
    info->UnicodeCoding = !utf16be_is_gsm_string(sms_message_utf16be);

    if ((s->err = GSM_EncodeMultiPartSMS(debug, info, sms)) != ERR_NONE) {
      status.err = "Failed to encode message";
      goto cleanup_sms_text;
    }

    status.parts_sent = 0;
    status.parts_total = sms->Number;

    /* For each SMS part... */
    for (unsigned int i = 0; i < sms->Number; i++) {

      status.finished = FALSE;
      status.message_part_index = i;

      sms->SMS[i].PDU = SMS_Submit;

      /* Copy destination phone number:
           This is a fixed-size buffer; size was already checked above. */

      CopyUnicodeString(sms->SMS[i].SMSC.Number, smsc->Number);

      CopyUnicodeString(
        sms->SMS[i].Number, (unsigned char *) sms_destination_number
      );

      /* Transmit a single message part */
      if ((s->err = GSM_SendSMS(s->sm, &sms->SMS[i])) != ERR_NONE) {
        status.parts[i].err = "Message transmission failed";
        continue;
      }

      for (;;) {
        /* Wait for reply */
        GSM_ReadDevice(s->sm, TRUE);

        if (status.finished) {
          break;
        }
      }

      if (!status.parts[i].transmitted) {
        status.parts[i].err = "Message delivery failed";
        continue;
      }

      status.parts_sent++;
    }

    cleanup_sms_text:
      status.message_index = ++message_index;
      free(sms_message_utf16be);

    cleanup_transmit_status:
      print_json_transmit_status(s, sms, &status, is_start);
      free(sms_destination_number);

    cleanup_end:
      is_start = FALSE;
  }

  cleanup_sms:

    free(sms);
    free(smsc);
    free(info);
    printf("]\n");
  
  cleanup:

    return rv;
}
Example #2
0
/* Find one multi SMS to sending and return it (or return ERR_EMPTY)
 * There is also set ID for SMS
 * File extension convention:
 * OUTxxxxx.txt : normal text SMS
 * Options appended to the extension applying to this SMS only:
 * d: delivery report requested
 * f: flash SMS
 * b: WAP bookmark as name,URL
 * e.g. OUTG20040620_193810_123_+4512345678_xpq.txtdf
 * is a flash text SMS requesting delivery reports
 */
static GSM_Error SMSDFiles_FindOutboxSMS(GSM_MultiSMSMessage * sms, GSM_SMSDConfig * Config, char *ID)
{
	GSM_MultiPartSMSInfo SMSInfo;
	GSM_WAPBookmark Bookmark;
	char FileName[100], FullName[400];
	unsigned char Buffer[(GSM_MAX_SMS_LENGTH * GSM_MAX_MULTI_SMS + 1) * 2];
	unsigned char Buffer2[(GSM_MAX_SMS_LENGTH * GSM_MAX_MULTI_SMS + 1) * 2];
	FILE *File;
	int i, len, phlen;
	char *pos1, *pos2, *options = NULL;
	gboolean backup = FALSE;
#ifdef GSM_ENABLE_BACKUP
	GSM_SMS_Backup smsbackup;
	GSM_Error error;
#endif
#ifdef WIN32
	struct _finddata_t c_file;
	intptr_t hFile;

	strcpy(FullName, Config->outboxpath);
	strcat(FullName, "OUT*.txt*");
	hFile = _findfirst(FullName, &c_file);
	if (hFile == -1) {
		strcpy(FullName, Config->outboxpath);
		strcat(FullName, "OUT*.smsbackup*");
		hFile = _findfirst(FullName, &c_file);
		backup = TRUE;
	}
	if (hFile == -1) {
		return ERR_EMPTY;
	} else {
		strcpy(FileName, c_file.name);
	}
	_findclose(hFile);
#elif defined(HAVE_DIRBROWSING)
	struct dirent **namelist = NULL;
	int cur_file, num_files;
	char *pos;

	strcpy(FullName, Config->outboxpath);

	FullName[strlen(Config->outboxpath) - 1] = '\0';

	num_files = scandir(FullName, &namelist, 0, alphasort);

	for (cur_file = 0; cur_file < num_files; cur_file++) {
		/* Hidden file or current/parent directory */
		if (namelist[cur_file]->d_name[0] == '.') {
			continue;
		}
		/* We care only about files starting with out */
		if (strncasecmp(namelist[cur_file]->d_name, "out", 3) != 0) {
			continue;
		}
		/* Check extension */
		pos = strrchr(namelist[cur_file]->d_name, '.');
		if (pos == NULL) {
			continue;
		}
		if (strncasecmp(pos, ".txt", 4) == 0) {
			/* We have found text file */
			backup = FALSE;
			break;
		}
		if (strncasecmp(pos, ".smsbackup", 10) == 0) {
			/* We have found a SMS backup file */
			backup = TRUE;
			break;
		}
	}
	/* Remember file name */
	if (cur_file < num_files) {
		strcpy(FileName, namelist[cur_file]->d_name);
	}
	/* Free scandir result */
	for (i = 0; i < num_files; i++) {
		free(namelist[i]);
	}
	free(namelist);
	namelist = NULL;
	/* Did we actually find something? */
	if (cur_file >= num_files) {
		return ERR_EMPTY;
	}
#else
	return ERR_NOTSUPPORTED;
#endif
	strcpy(FullName, Config->outboxpath);
	strcat(FullName, FileName);

	if (backup) {
#ifdef GSM_ENABLE_BACKUP
		/* Remember ID */
		strcpy(ID, FileName);
		/* Load backup */
		GSM_ClearSMSBackup(&smsbackup);
		error = GSM_ReadSMSBackupFile(FullName, &smsbackup);
		if (error != ERR_NONE) {
			return error;
		}
		/* Copy it to our message */
		sms->Number = 0;
		for (i = 0; smsbackup.SMS[i] != NULL; i++) {
			sms->SMS[sms->Number++] = *smsbackup.SMS[i];
		}
		/* Free memory */
		GSM_FreeSMSBackup(&smsbackup);

		/* Set delivery report flag */
		if (sms->SMS[0].PDU == SMS_Status_Report) {
			Config->currdeliveryreport = 1;
		} else {
			Config->currdeliveryreport = -1;
		}

#else
		SMSD_Log(DEBUG_ERROR, Config, "SMS backup loading disabled at compile time!");
		return ERR_DISABLED;

#endif
	} else {
		options = strrchr(FileName, '.') + 4;

		File = fopen(FullName, "rb");
		if (File == NULL) {
			return ERR_CANTOPENFILE;
		}
		len = fread(Buffer, 1, sizeof(Buffer) - 2, File);
		fclose(File);

		if ((len < 2) || (len >= 2 && ((Buffer[0] != 0xFF || Buffer[1] != 0xFE) && (Buffer[0] != 0xFE || Buffer[1] != 0xFF)))) {
			if (len > GSM_MAX_SMS_LENGTH * GSM_MAX_MULTI_SMS)
				len = GSM_MAX_SMS_LENGTH * GSM_MAX_MULTI_SMS;
			EncodeUnicode(Buffer2, Buffer, len);
			len = len * 2;
			memmove(Buffer, Buffer2, len);
			Buffer[len] = 0;
			Buffer[len + 1] = 0;
		} else {
			Buffer[len] = 0;
			Buffer[len + 1] = 0;
			/* Possibly convert byte order */
			ReadUnicodeFile(Buffer2, Buffer);
		}

		GSM_ClearMultiPartSMSInfo(&SMSInfo);
		sms->Number = 0;

		SMSInfo.ReplaceMessage = 0;
		SMSInfo.Entries[0].Buffer = Buffer2;
		SMSInfo.Class = -1;
		SMSInfo.EntriesNum = 1;
		Config->currdeliveryreport = -1;
		if (strchr(options, 'd'))
			Config->currdeliveryreport = 1;
		if (strchr(options, 'f'))
			SMSInfo.Class = 0;	/* flash SMS */

		if (strcasecmp(Config->transmitformat, "unicode") == 0) {
			SMSInfo.Entries[0].ID = SMS_ConcatenatedTextLong;
			SMSInfo.UnicodeCoding = TRUE;
		} else if (strcasecmp(Config->transmitformat, "7bit") == 0) {
			SMSInfo.Entries[0].ID = SMS_ConcatenatedTextLong;
			SMSInfo.UnicodeCoding = FALSE;
		} else {
			/* auto */
			SMSInfo.Entries[0].ID = SMS_ConcatenatedAutoTextLong;
		}

		if (strchr(options, 'b')) {	// WAP bookmark as title,URL
			SMSInfo.Entries[0].Buffer = NULL;
			SMSInfo.Entries[0].Bookmark = &Bookmark;
			SMSInfo.Entries[0].ID = SMS_NokiaWAPBookmarkLong;
			SMSInfo.Entries[0].Bookmark->Location = 0;
			pos2 = mywstrstr(Buffer2, "\0,");
			if (pos2 == NULL) {
				pos2 = Buffer2;
			} else {
				*pos2 = '\0';
				pos2++;
				*pos2 = '\0';
				pos2++;	// replace comma by zero
			}

			len = UnicodeLength(Buffer2);
			if (len > 50) {
				len = 50;
			}
			memmove(&SMSInfo.Entries[0].Bookmark->Title, Buffer2, len * 2);
			pos1 = &SMSInfo.Entries[0].Bookmark->Title[0] + len * 2;
			*pos1 = '\0';
			pos1++;
			*pos1 = '\0';

			len = UnicodeLength(pos2);
			if (len > 255) {
				len = 255;
			}
			memmove(&SMSInfo.Entries[0].Bookmark->Address, pos2, len * 2);
			pos1 = &SMSInfo.Entries[0].Bookmark->Address[0] + len * 2;
			*pos1 = '\0';
			pos1++;
			*pos1 = '\0';
		}

		GSM_EncodeMultiPartSMS(GSM_GetDebug(Config->gsm), &SMSInfo, sms);

		strcpy(ID, FileName);
		pos1 = FileName;
		for (i = 1; i <= 3 && pos1 != NULL; i++) {
			pos1 = strchr(++pos1, '_');
		}
		if (pos1 != NULL) {
			/* OUT<priority><date>_<time>_<serialno>_<phone number>_<anything>.txt */
			pos2 = strchr(++pos1, '_');
			if (pos2 != NULL) {
				phlen = strlen(pos1) - strlen(pos2);
			} else {
				/* something wrong */
				return ERR_UNKNOWN;
			}
		} else if (i == 2) {
			/* OUTxxxxxxx.txt or OUTxxxxxxx */
			pos1 = &FileName[3];
			pos2 = strchr(pos1, '.');
			if (pos2 == NULL) {
				phlen = strlen(pos1);
			} else {
				phlen = strlen(pos1) - strlen(pos2);
			}
		} else if (i == 4) {
			/* OUT<priority>_<phone number>_<serialno>.txt */
			pos1 = strchr(FileName, '_');
			pos2 = strchr(++pos1, '_');
			phlen = strlen(pos1) - strlen(pos2);
		} else {
			/* something wrong */
			return ERR_UNKNOWN;
		}

		for (len = 0; len < sms->Number; len++) {
			EncodeUnicode(sms->SMS[len].Number, pos1, phlen);
		}
	}

	if (sms->Number != 0) {
		DecodeUnicode(sms->SMS[0].Number, Buffer);
		if (options != NULL && strchr(options, 'b')) {	// WAP bookmark as title,URL
			SMSD_Log(DEBUG_NOTICE, Config, "Found %i sms to \"%s\" with bookmark \"%s\" cod %i lgt %i udh: t %i l %i dlr: %i fls: %i",
				 sms->Number,
				 Buffer,
				 DecodeUnicodeString(SMSInfo.Entries[0].Bookmark->Address),
				 sms->SMS[0].Coding, sms->SMS[0].Length, sms->SMS[0].UDH.Type, sms->SMS[0].UDH.Length, Config->currdeliveryreport, SMSInfo.Class);
		} else {
			SMSD_Log(DEBUG_NOTICE, Config, "Found %i sms to \"%s\" with text \"%s\" cod %i lgt %i udh: t %i l %i dlr: %i fls: %i",
				 sms->Number,
				 Buffer,
				 DecodeUnicodeString(sms->SMS[0].Text),
				 sms->SMS[0].Coding, sms->SMS[0].Length, sms->SMS[0].UDH.Type, sms->SMS[0].UDH.Length, Config->currdeliveryreport, sms->SMS[0].Class);
		}
	} else {
		SMSD_Log(DEBUG_NOTICE, Config, "error: SMS-count = 0");
	}

	return ERR_NONE;
}
Example #3
0
	/* Class 1 message (normal) */
	SMSInfo.Class = 1;
	/* Message will be consist of one part */
	SMSInfo.EntriesNum = 1;
	/* No unicode */
	SMSInfo.UnicodeCoding = FALSE;
	/* The part has type long text */
	SMSInfo.Entries[0].ID = SMS_ConcatenatedTextLong;
	/* Encode message text */
	EncodeUnicode(message_unicode, message_text, strlen(message_text));
	SMSInfo.Entries[0].Buffer = message_unicode;

	printf("%s\n", DecodeUnicodeConsole(SMSInfo.Entries[0].Buffer));

	/* Encode message into PDU parts */
	error = GSM_EncodeMultiPartSMS(debug_info, &SMSInfo, &SMS);
	error_handler();

	/* Allocates state machine */
	s = GSM_AllocStateMachine();
	if (s == NULL)
		return 3;

	/*
	 * Enable state machine debugging to stderr
	 * Same could be achieved by just using global debug config.
	 */
	debug_info = GSM_GetDebug(s);
	GSM_SetDebugGlobal(FALSE, debug_info);
	GSM_SetDebugFileDescriptor(stderr, TRUE, debug_info);
	GSM_SetDebugLevel("textall", debug_info);