sms_user.module in SMS Framework 5
Provides integration between the SMS Framework and Drupal users.
File
modules/sms_user/sms_user.moduleView source
<?php
/**
* @file
* Provides integration between the SMS Framework and Drupal users.
*/
define('SMS_USER_PENDING', 1);
define('SMS_USER_CONFIRMED', 2);
/**
* Send a message to a user.
*/
function sms_user_send($uid, $message) {
$account = user_load($uid);
if ($account->sms_user[0]['status'] == 2) {
return sms_send($account->sms_user[0]['number'], $message, $account->sms_user[0]['gateway']);
}
else {
return FALSE;
}
}
/**
* Returns the uid of the owner of a number.
*/
function sms_user_get_uid($number, $status = NULL) {
$sql = "SELECT uid FROM {sms_user} WHERE number = '%s'";
$arguments = array(
$number,
);
if (isset($status)) {
$sql .= " AND status = %d";
$arguments[] = $status;
}
$data = db_fetch_array(db_query($sql, $arguments));
return $data['uid'];
}
/**
* Implementation of hook_menu().
*/
function sms_user_menu($may_cache) {
global $user;
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/smsframework/sms_user',
'title' => t('SMS User'),
'description' => t('Edit options for SMS and user integration.'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'sms_user_admin_settings',
),
'access' => user_access('administer sms_user'),
'type' => MENU_NORMAL_ITEM,
);
}
else {
if (arg(0) == 'user' && is_numeric(arg(1))) {
$items[] = array(
'path' => 'user/' . arg(1) . '/mobile',
'title' => t('Mobile settings'),
'callback' => 'sms_user_settings',
'callback arguments' => array(
'sms_user_form',
),
'access' => user_access('administer users') || $user->uid == arg(1),
'type' => MENU_LOCAL_TASK,
);
}
}
return $items;
}
/**
* Implementation of hook_perm()
*/
function sms_user_perm() {
return array(
'administer sms_user',
);
}
/**
* Implementation of hook_sms_send().
*/
function sms_user_sms_send(&$number, &$message, &$options, &$gateway) {
if (variable_get('sms_user_sleep', 1) && ($uid = sms_user_get_uid($number))) {
$account = user_load(array(
'uid' => $uid,
'status' => 1,
));
if (!empty($account->sms_user['sleep_enabled']) && _sms_user_sleep_active($account)) {
unset($gateway['send']);
watchdog('sms', t('Message was not sent to @user due to sleep settings.', array(
'@user' => $account->name,
)));
}
}
}
function _sms_user_sleep_active($account) {
$current_hour = date('G');
if ($account->sms_user['sleep_start_time'] <= $current_hour && $account->sms_user['sleep_end_time'] > $current_hour) {
return TRUE;
}
return FALSE;
}
/**
* Menu callback; provides the forms for adding and confirming a user's mobile number.
*/
function sms_user_settings($register = FALSE) {
$account = user_load(array(
'uid' => arg(1),
));
switch (isset($account->sms_user) ? $account->sms_user[0]['status'] : 0) {
case 0:
$output = drupal_get_form('sms_user_settings_add_form', $account);
break;
case SMS_USER_PENDING:
$output = drupal_get_form('sms_user_settings_confirm_form', $account);
break;
case SMS_USER_CONFIRMED:
$output = drupal_get_form('sms_user_settings_reset_form', $account);
break;
}
if (variable_get('sms_user_sleep', 1)) {
$output .= drupal_get_form('sms_user_settings_sleep_form', $account);
}
return $output;
}
function sms_user_settings_add_form($account) {
$form = sms_send_form();
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Confirm number'),
);
return $form;
}
function sms_user_settings_add_form_validate($form_id, $form_values) {
if ($error = sms_user_validate_number($form_values['number'])) {
form_set_error('number', $error);
}
}
function sms_user_settings_add_form_submit($form_id, $form_values, $account = NULL) {
if (!$account) {
$account = user_load(array(
'uid' => arg(1),
));
}
sms_user_send_confirmation($account, $form_values['number'], $form_values['gateway']);
}
function sms_user_settings_confirm_form($account) {
$form['number'] = array(
'#type' => 'item',
'#title' => t('Number'),
'#value' => $account->sms_user[0]['number'],
);
$form['confirm_code'] = array(
'#type' => 'textfield',
'#title' => t('Confirmation code'),
'#description' => t('Enter the confirmation code that was sent to your phone.'),
'#size' => 4,
'#maxlength' => 4,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Confirm number'),
);
$form['reset'] = array(
'#type' => 'submit',
'#value' => t('Delete & start over'),
);
return $form;
}
function sms_user_settings_confirm_form_validate($form_id, $form_values) {
if ($form_values['op'] == t('Confirm number')) {
$account = user_load(array(
'uid' => arg(1),
));
if ($form_values['confirm_code'] != $account->sms_user[0]['code']) {
form_set_error('confirm_code', t('The confirmation code is invalid.'));
}
}
}
function sms_user_settings_confirm_form_submit($form_id, $form_values) {
$account = user_load(array(
'uid' => arg(1),
));
if ($form_values['op'] == t('Delete & start over')) {
sms_user_delete($account->uid, 0);
}
else {
$data[0] = array(
'number' => $account->sms_user[0]['number'],
'status' => SMS_USER_CONFIRMED,
'gateway' => $account->sms_user[0]['gateway'],
);
user_save($account, array(
'sms_user' => $data,
), 'mobile');
}
}
function sms_user_settings_reset_form($account) {
$form['sms_user']['number'] = array(
'#type' => 'item',
'#title' => t('Your number'),
'#value' => $account->sms_user[0]['number'],
'#description' => t('Your number has been confirmed.'),
);
$form['reset'] = array(
'#type' => 'submit',
'#value' => t('Delete & start over'),
);
return $form;
}
function sms_user_settings_reset_form_submit($form_id, $form_values) {
$account = user_load(array(
'uid' => arg(1),
));
sms_user_delete($account->uid, 0);
drupal_set_message(t('Your mobile information has been removed'), 'status');
}
function sms_user_settings_sleep_form($account) {
$form['sleep'] = array(
'#type' => 'fieldset',
'#title' => t('Sleep Time'),
'#collapsible' => TRUE,
);
$form['sleep']['sleep_enabled'] = array(
'#type' => 'checkbox',
'#title' => t('Disable messages between these hours'),
'#description' => t('If enabled, you will not receive messages between the specified hours.'),
'#default_value' => isset($account->sms_user['sleep_enabled']) ? $account->sms_user['sleep_enabled'] : NULL,
);
// Determine whether to use the 24-hour or 12-hour clock based on site settings
if (strpos(variable_get('date_format_short', 'm/d/Y - H:i'), 'g')) {
$format = 'g A';
}
else {
$format = 'H:00';
}
// Build the list of options based on format
$hour = 0;
while ($hour < 24) {
$options[$hour] = date($format, mktime($hour));
$hour++;
}
$form['sleep']['sleep_start_time'] = array(
'#type' => 'select',
'#multiple' => FALSE,
'#options' => $options,
'#default_value' => isset($account->sms_user['sleep_start_time']) ? $account->sms_user['sleep_start_time'] : NULL,
);
$form['sleep']['sleep_end_time'] = array(
'#type' => 'select',
'#multiple' => FALSE,
'#options' => $options,
'#default_value' => isset($account->sms_user['sleep_end_time']) ? $account->sms_user['sleep_end_time'] : NULL,
);
$form['sleep']['save'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
return $form;
}
function sms_user_settings_sleep_form_submit($form_id, $form_values) {
$account = user_load(array(
'uid' => arg(1),
));
$data = $account->sms_user;
$data['sleep_enabled'] = $form_values['sleep_enabled'];
$data['sleep_start_time'] = $form_values['sleep_start_time'];
$data['sleep_end_time'] = $form_values['sleep_end_time'];
user_save($account, array(
'sms_user' => $data,
), 'mobile');
drupal_set_message(t('The changes have been saved.'), 'status');
}
function sms_user_send_confirmation($account, $number, $options) {
$code = rand(1000, 9999);
$number = sms_formatter($number);
$data[0] = array(
'number' => $number,
'status' => SMS_USER_PENDING,
'code' => $code,
'gateway' => $options,
);
user_save($account, array(
'sms_user' => $data,
), 'mobile');
sms_send($number, _sms_user_confirm_message($code), $options);
}
function sms_user_validate_number(&$number) {
if ($error = sms_validate_number($number)) {
return $error;
}
elseif (sms_user_get_uid($number, SMS_USER_CONFIRMED)) {
return t('This phone number is already registered to another user.');
}
}
/**
* Deletes a user's mobile information from the database
*
* @param $uid
* The uid of the user who's data is to be removed.
*
* @param $delta
* The delta value of the number. Defaults to 'all' which will delete all numbers.
*/
function sms_user_delete($uid, $delta = 'all') {
$db_args = array(
$uid,
);
if (is_numeric($delta)) {
$delta_where = 'AND delta = %d';
$db_args[] = $delta;
}
db_query("DELETE FROM {sms_user} WHERE uid = %d {$delta_where}", $db_args);
}
function sms_user_user($op, &$edit, &$account, $category = NULL) {
switch ($op) {
case 'load':
return sms_user_load($edit, $account, $category);
case 'update':
case 'insert':
return sms_user_save($edit, $account, $category);
case 'register':
return sms_user_register();
case 'delete':
return sms_user_delete($account->uid);
case 'validate':
if (!empty($edit['sms_user']) && (variable_get('sms_user_registration_form', 0) == 2 || strlen($edit['sms_user'][0]['number']))) {
if ($error = sms_user_validate_number($edit['sms_user'][0]['number'])) {
form_set_error('sms_user][0][number', $error);
}
}
break;
case 'login':
// Check if first it's the user's first time logging in.
if (!$account->access && $account->sms_user[0]['number']) {
sms_user_send_confirmation($account, $account->sms_user[0]['number'], $account->sms_user[0]['gateway']);
drupal_set_message(t('A confirmation message has been sent to your mobile phone. Please !link.', array(
'!link' => l(t('confirm your number'), 'user/' . $account->uid . '/mobile'),
)), 'status');
}
break;
}
}
function sms_user_load(&$edit, &$account, $category) {
$result = db_query("SELECT number, delta, status, code, gateway FROM {sms_user} WHERE uid = %d", $account->uid);
while ($data = db_fetch_array($result)) {
if ($data) {
$account->sms_user[$data['delta']] = array(
'number' => $data['number'],
'status' => $data['status'],
'code' => $data['code'],
'gateway' => unserialize($data['gateway']),
);
}
}
}
function sms_user_save(&$edit, &$account, $category) {
if (($category == 'mobile' || $category == 'account') && $edit['sms_user'][0]['number']) {
foreach ($edit['sms_user'] as $delta => $number) {
if (is_numeric($delta)) {
$db_values = array(
$number['number'],
$number['status'],
isset($number['code']) ? $number['code'] : NULL,
serialize($number['gateway']),
);
if (isset($account->sms_user[$delta])) {
db_query("UPDATE {sms_user} SET number = '%s', status = %d, code = '%s', gateway = '%s'\n WHERE uid = %d AND delta = %d", array_merge($db_values, array(
$account->uid,
$delta,
)));
}
else {
db_query("INSERT INTO {sms_user} (number, status, code, gateway, uid, delta)\n VALUES ('%s', %d, '%s', '%s', %d, %d)", array_merge($db_values, array(
$account->uid,
$delta,
)));
}
}
}
$edit['sms_user'][0] = NULL;
}
}
function _sms_user_confirm_message($code) {
$text_format = variable_get('sms_user_confirmation_message', '[site-name] confirmation code: [confirm-code]');
$text = token_replace_multiple($text_format, array(
'sms_user' => array(
'confirm-code' => $code,
),
));
return $text;
}
function sms_user_register() {
if (variable_get('sms_user_registration_form', 0)) {
$form['sms_user'] = array(
'#type' => 'fieldset',
'#title' => t('Mobile settings'),
'#description' => t('You will receive a message to confirm your mobile information upon login.'),
'#collapsible' => TRUE,
'#tree' => TRUE,
);
$required = FALSE;
if (variable_get('sms_user_registration_form', 0) == 2) {
$required = TRUE;
}
$form['sms_user'][0] = sms_send_form($required);
$form['sms_user'][0]['status'] = array(
'#type' => 'value',
'#value' => 1,
);
return $form;
}
}
function sms_user_admin_settings() {
$form['sms_user_registration_form'] = array(
'#type' => 'radios',
'#title' => t('Show mobile fields during user registration'),
'#description' => t('Specify if the site should collect mobile information during registration.'),
'#options' => array(
t('Disabled'),
t('Optional'),
t('Required'),
),
'#default_value' => variable_get('sms_user_registration_form', 0),
);
$form['sms_user_confirmation_message'] = array(
'#type' => 'textfield',
'#title' => t('Confirmation message format'),
'#default_value' => variable_get('sms_user_confirmation_message', '[site-name] confirmation code: [confirm-code]'),
'#description' => t('Specify the format for confirmation messages. Keep this as short as possible.'),
'#size' => 40,
'#maxlength' => 255,
);
$form['tokens'] = array(
'#type' => 'fieldset',
'#title' => t('Available replacement patterns'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['tokens']['content']['#value'] = theme('token_help', 'sms_user');
$form['sms_user_sleep'] = array(
'#type' => 'checkbox',
'#title' => t('Enable sleep hours'),
'#description' => t('If checked, users will be able to specifiy hours during which they will not receive messages from the site.'),
'#default_value' => variable_get('sms_user_sleep', 1),
);
return system_settings_form($form);
}
/**
* Implementation of hook_token_values()
*/
function sms_user_token_values($type, $object = NULL, $options = array()) {
global $user;
$values = array();
switch ($type) {
case 'sms_user':
$values['confirm-code'] = $object['confirm-code'];
$values['mobile-url'] = url("user/{$user->uid}/mobile", NULL, NULL, TRUE);
break;
}
return $values;
}
/**
* Implementation of hook_token_list()
*/
function sms_user_token_list($type = 'all') {
if ($type = 'sms_user') {
$tokens['sms_user']['confirm-code'] = t('The mobile confirmation code for the user.');
$tokens['sms_user']['mobile-url'] = t('The URL for the user\'s mobile settings page.');
}
return $tokens;
}
/**
* Implementation of hook_sms_incoming().
*/
function sms_user_sms_incoming($op, $number, $message) {
switch ($op) {
case 'pre process':
sms_user_authenticate($number);
break;
case 'post process':
sms_user_logout();
break;
}
}
/**
* Authenticate a user based on mobile number.
*
* @param $number
* The number to authenticate against. For security, this should only be
* provided by incoming messages, not through user input.
*/
function sms_user_authenticate($number) {
global $user;
$uid = sms_user_get_uid($number);
if ($account = user_load(array(
'uid' => $uid,
'status' => 1,
))) {
$user = $account;
watchdog('sms', t('%name was authenticated using SMS.', array(
'%name' => $user->name,
)));
return $user;
}
}
function sms_user_logout() {
global $user;
// Destroy the current session:
session_destroy();
$user = drupal_anonymous_user();
}
/*
* Implementation of hook_sms_receive()
* Match an incoming message to a user
*/
function sms_user_sms_receive(&$node, $sms_message) {
// is $sms_message['from'] a general case?
$number = $sms_message['from'];
// how is this be handled with international numbers? do we need to remove +44 for UK?
// should be able to test when we get Chinese SIM card
if (substr($number, 0, 1) == '1') {
// remove leading '1', sms_user doesn't store it...
$number = substr($number, 1);
}
$uid = sms_user_get_uid($number);
$account = user_load(array(
'uid' => $uid,
));
$node->uid = $account->uid;
$node->name = $account->name;
}
Functions
Constants
Name | Description |
---|---|
SMS_USER_CONFIRMED | |
SMS_USER_PENDING | @file Provides integration between the SMS Framework and Drupal users. |