diff --git a/bbb.module b/bbb.module
index 2aa4da0..d4fc614 100644
--- a/bbb.module
+++ b/bbb.module
@@ -18,19 +18,23 @@
  */
 
 // API version
-define('BBB_API_VERSION', variable_get('bbb_api_version', NULL));
+define('BIGBLUEBUTTON_API_VERSION', variable_get('bbb_api_version', NULL));
+define('BIGBLUEBUTTON_GET_MEETING_INFO_URL', '/api/getMeetingInfo');
+define('BIGBLUEBUTTON_CREATE_URL', '/api/create');
+define('BIGBLUEBUTTON_JOIN_URL', '/api/join');
+define('BIGBLUEBUTTON_IS_MEETING_RUNNING_URL', '/api/isMeetingRunning');
+define('BIGBLUEBUTTON_END_MEETING_URL', '/api/endMeeting');
 // Security Salt
 // see /var/lib/tomcat6/webapps/bigbluebutton/WEB-INF/classes/bigbluebutton.properties
-define('BBB_API_SECURITY_SALT', variable_get('bbb_security_salt', '76b71974198f26ecc5a594eddddf49d1'));
+define('BIGBLUEBUTTON_SECURITY_SALT', variable_get('bbb_security_salt', 'fdskj32988923689mn3m23kj903jd728'));
+define('BIGBLUEBUTTON_BASE_URL', variable_get('bbb_base_url', 'http://example.com/bigbluebutton'));
 
 // Define default settings
 define('BBB_DISPLAY_MODE',   variable_get('bbb_display_mode', 'inline'));
 define('BBB_DISPLAY_HEIGHT', variable_get('bbb_display_height', '580px'));
 define('BBB_DISPLAY_WIDTH',  variable_get('bbb_display_width', '100%'));
 
-if (BBB_API_VERSION) {
-  include_once(drupal_get_path('modules', 'bbb') . 'includes/api-' . BBB_API_VERSION . '.bbb.inc');
-}
+include_once(drupal_get_path('modules', 'bbb') . 'includes/api.bbb.inc');
 
 /* Drupal Hooks */
 
@@ -123,7 +127,7 @@ function bbb_menu() {
     'access callback' => 'bbb_access_attendee',
     'access arguments' => array(1),
     'type' => MENU_CALLBACK,
-    'file' => 'includes/api-' . BBB_API_VERSION . '.bbb.inc',
+    'file' => 'includes/api-' . BIGBLUEBUTTON_API_VERSION . '.bbb.inc',
   );
   $items['admin/config/media/bigbluebutton'] = array(
     'title' => 'Big Blue Button meetings',
@@ -251,7 +255,13 @@ function bbb_form_alter(&$form, &$form_state, $form_id) {
         '#title' => t('Display meeting status on node'),
         '#default_value' => variable_get('bbb_content_type_show_status_' . $form['#node_type']->type, FALSE),
       );
-      
+
+      $form['bbb']['bbb_content_type_moderator_required'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Require a moderator present to run the meeting.'),
+        '#default_value' => variable_get('bbb_content_type_moderator_required_' . $form['#node_type']->type, FALSE),
+      );
+
       $form['bbb']['bbb_content_type_welcome'] = array(
         '#title' => t('Welcome message'),
         '#type' => 'textfield',
@@ -287,66 +297,68 @@ function bbb_form_alter(&$form, &$form_state, $form_id) {
         '#maxlength' => 255,
         '#description' => t('The URL that the Big Blue Button client will go to after users click the OK button on the <em>You have been logged out message</em>.'),
       );
-    }
+      //}
   }
 
   // Node edit form
-  $node_type = $form['#type']['#value'];
-  if (drupal_substr($form_id, (drupal_strlen($form_id) - 10), 10) == '_node_form' &&
-      bbb_is_meeting_type($node_type) &&
-      user_access('administer big blue button')) {
-    if (is_numeric($form['nid']['#value'])) {
-      $meeting = bbb_get_meeting($form['nid']['#value']);
-    }
+  if (array_key_exists('#node_edit_form',$form)) {
+    $node_type = $form['type']['#value'];
+    if (drupal_substr($form_id, (drupal_strlen($form_id) - 10), 10) == '_node_form' &&
+        bbb_is_meeting_type($node_type) &&
+        user_access('administer big blue button')) {
+      if (is_numeric($form['nid']['#value'])) {
+        $meeting = bbb_get_meeting($form['nid']['#value']);
+      }
 
-    $form['bbb'] = array(
-      '#title' => t('Meeting settings'),
-      '#type' => 'fieldset',
-      '#description' => t("The following settings maybe changed until the meeting first starts."),
-      '#collapsible' => TRUE,
-      '#collapsed' => TRUE,
-      '#tree' => TRUE,
-    );
-    $form['bbb']['welcome'] = array(
-      '#title' => t('Welcome message'),
-      '#type' => 'textfield',
-      '#default_value' => variable_get('bbb_content_type_welcome_' . $node_type, ''),
-      '#maxlength' => 255,
-      '#description' => t('A welcome message that gets displayed on the chat window when the participant joins. You can include keywords (%%CONFNAME%%, %%DIALNUM%%, %%CONFNUM%%) which will be substituted automatically.'),
-      '#attributes' => $meeting->meetingID ? array('disabled' => 'disabled') : array(),
-    );
-    $form['bbb']['dialNumber'] = array(
-      '#title' => t('Dial number'),
-      '#type' => 'textfield',
-      '#default_value' => variable_get('bbb_content_type_dialNumber_' . $node_type, ''),
-      '#maxlength' => 32,
-      '#description' => t('The dial access number that participants can call in using regular phone.'),
-      '#attributes' => $meeting->meetingID ? array('disabled' => 'disabled') : array(),
-    );
-    $form['bbb']['moderatorPW'] = array(
-      '#title' => t('Moderator password'),
-      '#type' => 'textfield',
-      '#default_value' => variable_get('bbb_content_type_moderatorPW_' . $node_type, ''),
-      '#maxlength' => 32,
-      '#description' => t('The password that will be required for moderators to join the meeting or for certain administrative actions (i.e. ending a meeting).'),
-      '#attributes' => $meeting->meetingID ? array('disabled' => 'disabled') : array(),
-    );
-    $form['bbb']['attendeePW'] = array(
-      '#title' => t('Attendee password'),
-      '#type' => 'textfield',
-      '#default_value' => variable_get('bbb_content_type_attendeePW_' . $node_type, ''),
-      '#maxlength' => 32,
-      '#description' => t('The password that will be required for attendees to join the meeting.'),
-      '#attributes' => $meeting->meetingID ? array('disabled' => 'disabled') : array(),
-    );
-    $form['bbb']['logoutURL'] = array(
-      '#title' => t('Logout URL'),
-      '#type' => 'textfield',
-      '#default_value' => variable_get('bbb_content_type_logoutURL_' . $node_type, ''),
-      '#maxlength' => 255,
-      '#description' => t('The URL that the Big Blue Button client will go to after users click the OK button on the <em>You have been logged out message</em>.'),
-      '#attributes' => $meeting->meetingID ? array('disabled' => 'disabled') : array(),
-    );
+      $form['bbb'] = array(
+        '#title' => t('Meeting settings'),
+        '#type' => 'fieldset',
+        '#description' => t("The following settings maybe changed until the meeting first starts."),
+        '#collapsible' => TRUE,
+        '#collapsed' => TRUE,
+        '#tree' => TRUE,
+      );
+      $form['bbb']['welcome'] = array(
+        '#title' => t('Welcome message'),
+        '#type' => 'textfield',
+        '#default_value' => !empty($meeting->welcome) ? $meeting->welcome : variable_get('bbb_content_type_welcome_' . $node_type, ''),
+        '#maxlength' => 255,
+        '#description' => t('A welcome message that gets displayed on the chat window when the participant joins. You can include keywords (%%CONFNAME%%, %%DIALNUM%%, %%CONFNUM%%) which will be substituted automatically.'),
+        '#attributes' => !empty($meeting->meetingid) ? array('disabled' => 'disabled') : array(),
+      );
+      $form['bbb']['dialNumber'] = array(
+        '#title' => t('Dial number'),
+        '#type' => 'textfield',
+        '#default_value' => !empty($meeting->dialnumber) ? $meeting->dialnumber : variable_get('bbb_content_type_dialNumber_' . $node_type, ''),
+        '#maxlength' => 32,
+        '#description' => t('The dial access number that participants can call in using regular phone.'),
+        '#attributes' => !empty($meeting->meetingid) ? array('disabled' => 'disabled') : array(),
+      );
+      $form['bbb']['moderatorPW'] = array(
+        '#title' => t('Moderator password'),
+        '#type' => 'textfield',
+        '#default_value' => !empty($meeting->moderatorpw) ? $meeting->moderatorpw : variable_get('bbb_content_type_moderatorPW_' . $node_type, ''),
+        '#maxlength' => 32,
+        '#description' => t('The password that will be required for moderators to join the meeting or for certain administrative actions (i.e. ending a meeting).'),
+        '#attributes' => !empty($meeting->meetingid) ? array('disabled' => 'disabled') : array(),
+      );
+      $form['bbb']['attendeePW'] = array(
+        '#title' => t('Attendee password'),
+        '#type' => 'textfield',
+        '#default_value' => !empty($meeting->attendeepw) ? $meeting->attendeepw : variable_get('bbb_content_type_attendeePW_' . $node_type, ''),
+        '#maxlength' => 32,
+        '#description' => t('The password that will be required for attendees to join the meeting.'),
+        '#attributes' => !empty($meeting->meetingid) ? array('disabled' => 'disabled') : array(),
+      );
+      $form['bbb']['logoutURL'] = array(
+        '#title' => t('Logout URL'),
+        '#type' => 'textfield',
+        '#default_value' => !empty($meeting->logouturl) ? $meeting->logouturl : variable_get('bbb_content_type_logoutURL_' . $node_type, ''),
+        '#maxlength' => 255,
+        '#description' => t('The URL that the Big Blue Button client will go to after users click the OK button on the <em>You have been logged out message</em>.'),
+        '#attributes' => !empty($meeting->meetingid) ? array('disabled' => 'disabled') : array(),
+      );
+    }
   }
 }
 
@@ -390,7 +402,7 @@ function bbb_node_view($node, $view_mode, $langcode) {
   $meeting = bbb_get_meeting($node->nid);
 
   $node->content['bbb_meeting_status'] = array(
-        '#value' => theme('bbb_meeting_status', array('meeting' => $meeting)),
+        '#markup' => theme('bbb_meeting_status', array('meeting' => $meeting)),
         '#weight' => 10,
   );
   $node->content['bbb_meeting_start'] = array(
@@ -405,8 +417,8 @@ function bbb_node_view($node, $view_mode, $langcode) {
 
 function bbb_node_load($nodes, $types) {
   foreach($nodes as $node) {
-    if (bbb_is_meeting_type($nodes[$node->nid]->type)) {
-      $nodes[$node->nid]->bbb = bbb_get_meeting($nodes[$node->nid]->nid);
+    if (bbb_is_meeting_type($node->type)) {
+      $node->bbb = bbb_get_meeting($node->nid);
     }
   }
 }
@@ -465,19 +477,19 @@ function bbb_link($type, $object, $teaser = FALSE) {
 function bbb_theme($existing, $type, $theme, $path) {
   return array(
     'bbb_meeting' => array(
-      'arguments' => array('meeting' => NULL, 'mode' => NULL, 'params' => array()),
+      'variables' => array('meeting' => NULL, 'mode' => NULL, 'params' => array()),
     ),
     'bbb_meeting_status' => array(
-      'arguments' => array('meeting' => NULL),
+      'variables' => array('meeting' => NULL),
     ),
     'bbb_meeting_join_moderator' => array(
-      'arguments' => array('meeting' => NULL),
+      'variables' => array('meeting' => NULL),
     ),
     'bbb_meeting_join_attendee' => array(
-      'arguments' => array('meeting' => NULL),
+      'variables' => array('meeting' => NULL),
     ),
     'bbb_block_meeting' => array(
-      'arguments' => array('meeting' => NULL),
+      'variables' => array('meeting' => NULL),
     ),
   );
 }
@@ -494,9 +506,9 @@ function bbb_is_meeting_owner($nid, $account = NULL) {
   }
   $sql = "SELECT COUNT(nid) FROM {bbb_meetings} bm
            INNER JOIN {node} n ON bm.nid = n.nid
-           WHERE n.uid = %d
-             AND nid = %d";
-  $owner = db_result(db_query($sql, $account->uid, $nid));
+           WHERE n.uid = :uid
+             AND nid = :nid";
+  $owner = db_result(db_query($sql, array(':uid'=>$account->uid, ':nid' =>$nid)));
   return $owner ? TRUE : FALSE;
 }
 
@@ -526,24 +538,18 @@ function bbb_get_meeting($nid, $account = NULL, $cached = TRUE) {
     //debug($meeting);
 
     if ($meeting) {
-      $meeting->running = bbb_api_isMeetingRunning(array('meetingID' => $meeting->meetingid))->running ? TRUE : FALSE;
+      $meeting->running = bbb_api_isMeetingRunning(array('meetingID' => $meeting->meetingid));
       $meeting->url = array(
         'attend' => bbb_api_join(
           array(
-            'fullName' => $account->name,
+            'fullName' => property_exists($account,'name') ? $account->name : t('Anonymous'),
             'meetingID' => $meeting->meetingid,
             'password' => $meeting->attendeepw,
           )
         ),
         'moderate' => bbb_api_join(
           array(
-            'fullName' => $account->name,
-            'meetingID' => $meeting->meetingid,
-            'password' => $meeting->moderatorpw,
-          )
-        ),
-        'end' => bbb_api_end(
-          array(
+            'fullName' => property_exists($account,'name') ? $account->name : t('Anonymous'),
             'meetingID' => $meeting->meetingid,
             'password' => $meeting->moderatorpw,
           )
@@ -551,7 +557,7 @@ function bbb_get_meeting($nid, $account = NULL, $cached = TRUE) {
       );
       // Allow alteration for e.g. access control
       // Just implement hook_bbb_meeting_alter(&$data) {} in your module
-      drupal_alter('bbb_meeting', &$meeting);
+      drupal_alter('bbb_meeting', $meeting);
       // Static cache
       $meetings[$nid] = $meeting;
     }
@@ -618,7 +624,7 @@ function bbb_store_meeting($node, $params = array()) {
  * Delete meeting
  */
 function bbb_delete_meeting($nid) {
-  return db_query("DELETE FROM {bbb_meetings} WHERE nid = %d", $nid);
+  return db_query("DELETE FROM {bbb_meetings} WHERE nid = :nid", array(':nid'=>$nid));
 }
 
 /* Menu Callbacks */
@@ -646,31 +652,43 @@ function bbb_meeting_attend($node) {
 
   $params = array(
     'meetingID' => $meeting->meetingid,
-    'password' => $meeting->moderatorpw,
+    'password' => $meeting->attendeePW,
   );
   $status = bbb_api_getMeetingInfo($params);
-  if ($status->hasBeenForciblyEnded == 'true') {
+  if (property_exists('hasBeenForciblyEnded',$status) && $status->hasBeenForciblyEnded == 'true') {
     drupal_set_message('The meeting has been terminated and is not available for attending.');
     drupal_goto('node/' . $node->nid);
   }
 
   drupal_set_title($node->title);
   if ($meeting->running) {
-    if (BBB_DISPLAY_MODE == 'blank') {
+    if (BIGBLUEBUTTON_DISPLAY_MODE == 'blank') {
       bbb_redirect($node, $mode);
     }
   }
   else {
-    drupal_add_js('var bbb_check_status_url = ' . drupal_json_encode(url('node/' . $node->nid . '/meeting/status')), 'inline');
-    drupal_add_js(drupal_get_path('module', 'bbb') . '/js/check_status.bbb.js');
-    drupal_set_message(t('You signed up for this meeting. Please stay on this page, you will be redirected immediately after the meeting has started.'));
-    return node_show($node, NULL);
+    if ( variable_get('bbb_content_type_moderator_required_' . $node->type, FALSE)) {
+      drupal_add_js('var bbb_check_status_url = ' . drupal_json_encode(url('node/' . $node->nid . '/meeting/status')), 'inline');
+      drupal_add_js(drupal_get_path('module', 'bbb') . '/js/check_status.bbb.js');
+      drupal_set_message(t('You signed up for this meeting. Please stay on this page, you will be redirected immediately after the meeting has started.'));
+      return node_show($node, NULL);
+    } else {
+      if (empty($meeting->initialized)) {
+        if ($data = bbb_create_meeting($node, (array) $params)) {
+          // Update local data
+          bbb_update_meeting($node, array_merge((array) $meeting, (array) $data));
+        }
+      }
+      if (BIGBLUEBUTTON_DISPLAY_MODE == 'blank') {
+        bbb_redirect($node, $mode);
+      }
+    }
   }
   $variables = array(
-  	'meeting' => $meeting, 
-  	'mode' => $mode, 
-  	'height' => BBB_DISPLAY_HEIGHT, 
-  	'width' => BBB_DISPLAY_WIDTH
+  	'meeting' => $meeting,
+  	'mode' => $mode,
+  	'height' => BIGBLUEBUTTON_DISPLAY_HEIGHT,
+  	'width' => BIGBLUEBUTTON_DISPLAY_WIDTH
   );
   return theme('bbb_meeting', $variables);
 }
@@ -688,9 +706,10 @@ function bbb_meeting_moderate($node) {
   $meeting = bbb_get_meeting($node->nid);
 
   $params = array(
-    'meetingID' => $meeting->meetingID,
+    'meetingID' => $meeting->meetingid,
     'password' => $meeting->moderatorPW,
   );
+
   $status = bbb_api_getMeetingInfo($params);
 
   if ($status->hasBeenForciblyEnded == 'true') {
@@ -706,14 +725,14 @@ function bbb_meeting_moderate($node) {
       bbb_update_meeting($node, array_merge((array) $meeting, (array) $data));
     }
   }
-  if (BBB_DISPLAY_MODE == 'blank') {
+  if (BIGBLUEBUTTON_DISPLAY_MODE == 'blank') {
     bbb_redirect($node, $mode);
   }
   $variables = array(
-  	'meeting' => $meeting, 
-  	'mode' => $mode, 
-  	'height' => BBB_DISPLAY_HEIGHT, 
-  	'width' => BBB_DISPLAY_WIDTH
+  	'meeting' => $meeting,
+  	'mode' => $mode,
+  	'height' => BIGBLUEBUTTON_DISPLAY_HEIGHT,
+  	'width' => BIGBLUEBUTTON_DISPLAY_WIDTH
   );
   return theme('bbb_meeting', $variables);
 }
@@ -754,7 +773,7 @@ function bbb_end_confirm_form_submit($form, &$form_state) {
 function bbb_meeting_end($node) {
   $meeting = bbb_get_meeting($node->nid);
   $params = array(
-    'meetingID' => $meeting->meetingID,
+    'meetingID' => $meeting->meetingid,
     'password' => $meeting->moderatorPW,
   );
   $request = bbb_api_end($params);
@@ -811,7 +830,7 @@ function theme_bbb_meeting($meeting, $variables = array()) {
  */
 function theme_bbb_meeting_status($meeting) {
   $meeting = $meeting['meeting'];
-  if ($meeting->running) {
+  if (isset($meeting->running) && $meeting->running) {
     $output = '<div class="bbb-status-is-running">' . t('Status: Meeting is progress.') . '</div>';
   }
   else {
@@ -824,6 +843,7 @@ function theme_bbb_meeting_status($meeting) {
  * Theme meeting details block
  */
 function theme_bbb_block_meeting($meeting) {
+  $meeting = $meeting['meeting'];
   $output = '<div class="bbb-meeting-details">';
   if ($meeting->welcome) {
     $output .= '<div class="bbb-welcome">' . $meeting->welcome . '</div>';
diff --git a/includes/api.bbb.inc b/includes/api.bbb.inc
new file mode 100644
index 0000000..eb8b9f8
--- /dev/null
+++ b/includes/api.bbb.inc
@@ -0,0 +1,245 @@
+<?php
+/**
+* @file
+* BigBlueButton - Enables universities and colleges to deliver a high-quality
+* learning experience.
+*
+* @author
+* Stefan Auditor <stefan.auditor@erdfisch.de>
+*/
+
+/**
+* Create Meeting (create)
+*
+* @param ARRAY $params
+*   Associative array of additional url parameters. Components:
+*   - name: STRING (REQUIRED) A name for the meeting.
+*   - meetingID: STRING A meeting ID that can be used to identify this meeting
+*     by the third party application. This is optional, and if not supplied,
+*     BBB will generate a meeting token that can be used to identify the
+*     meeting.
+*   - attendeePW: STRING The password that will be required for attendees to
+*     join the meeting. This is optional, and if not supplied, BBB will assign
+*     a random password.
+*   - moderatorPW: STRING The password that will be required for moderators to
+*     join the meeting or for certain administrative actions (i.e. ending a
+*     meeting). This is optional, and if not supplied, BBB will assign a
+*     random password.
+*   - welcome: STRING A welcome message that gets displayed on the chat window
+*     when the participant joins. You can include keywords (%%CONFNAME%%,
+*     %%DIALNUM%%, %%CONFNUM%%) which will be substituted automatically. You
+*     can set a default welcome message on bigbluebutton.properties
+*   - dialNumber: STRING The dial access number that participants can call in
+*     using regular phone. You can set a default dial number on
+*     bigbluebutton.properties
+*   - logoutURL: STRING The URL that the BigBlueButton client will go to after
+*     users click the OK button on the 'You have been logged out message'.
+*     This overrides, the value for bigbluebutton.web.loggedOutUrl if defined
+*     in bigbluebutton.properties
+* @return OBJECT or FALSE
+*   - meetingToken: STRING The internal meeting token assigned by the API for
+*     this meeting. It can be used by subsequent calls for joining or
+*     otherwise modifying a meeting's status.
+*   - meetingID: STRING The meeting ID supplied by the third party app, or
+*     null if none was supplied. If can be used in conjunction with a password
+*     in subsequent calls for joining or otherwise modifying a meeting's
+*     status.
+*   - attendeePW: STRING The password that will be required for attendees to
+*     join the meeting. If you did not supply one, BBB will assign a random
+*     password.
+*   - moderatorPW: STRING The password that will be required for moderators to
+*     join the meeting or for certain administrative actions (i.e. ending a
+*     meeting). If you did not supply one, BBB will assign a random password.
+*
+* @see http://code.google.com/p/bigbluebutton/wiki/API#Create_Meeting_(create)
+*/
+function bbb_api_create($params = array()) {
+  $query_string = bbb_api_generate_querystring($params, 'create');
+  $request = BIGBLUEBUTTON_BASE_URL . BIGBLUEBUTTON_CREATE_URL . '?' . $query_string;
+  $xml = @simplexml_load_file($request);
+  $response = bbb_api_parse_response($xml);
+
+  if ($response->returncode == 'SUCCESS') {
+    unset($response->returncode);
+    return $response;
+  }
+  else {
+    watchdog('bigbluebutton', '%message', array('%message' => $response->message), WATCHDOG_ERROR);
+    return FALSE;
+  }
+}
+
+/**
+* Join Meeting (join)
+*
+* @param ARRAY $params
+*   Associative array of additional url parameters. Components:
+*   - fullName: STRING (REQUIRED) The full name that is to be used to identify
+*     this user to other conference attendees.
+*   - meetingToken: The internal meeting token assigned by the API for this
+*     meeting when it was created. Note that either the meetingToken or the
+*     meetingID along with one of the passwords must be passed into this call
+*     in order to determine which meeting to find.
+*   - meetingID: STRING If you specified a meeting ID when calling create,
+*     then you can use either the generated meeting token or your specified
+*     meeting ID to find meetings. This parameter takes your meeting ID.
+*   - password: STRING The password that this attendee is using. If the
+*     moderator password is supplied, he will be given moderator status (and
+*     the same for attendee password, etc)
+*   - redirectImmediately: BOOLEAN If this is passed as true, then BBB will
+*     not return a URL for you to redirect the user to, but will instead treat
+*     this as an entry URL and will immediately set up the client session and
+*     redirect the user into the conference.
+*     Values can be either a 1 (one) or a 0 (zero), indicating true or false
+*     respectively. Defaults to false.
+* @return STRING
+*   The URL that the user can be sent to in order to join the meeting. When
+*   they go to this URL, BBB will setup their client session and redirect them
+*   into the conference.
+*/
+function bbb_api_join($params) {
+  $query_string = bbb_api_generate_querystring($params, 'join');
+  return BIGBLUEBUTTON_BASE_URL . BIGBLUEBUTTON_JOIN_URL . '?' . $query_string;
+}
+
+/**
+* Is meeting running (isMeetingRunning)
+*
+* This call enables you to simply check on whether or not a meeting is running
+* by looking it up with either the token or your ID.
+*
+* @param ARRAY $params
+*   Associative array of additional url parameters. Components:
+*   - meetingToken: STRING The internal meeting token assigned by the API for
+*     this meeting when it was created.
+*   - meetingID: STRING If you specified a meeting ID when calling create,
+*     then you can use either the generated meeting token or your specified
+*     meeting ID to find meetings. This parameter takes your meeting ID.
+* @return BOOLEAN
+*   A string of either “true” or “false” that signals whether a meeting with
+*   this ID or token is currently running.
+*/
+function bbb_api_isMeetingRunning($params) {
+  $query_string = bbb_api_generate_querystring($params, 'isMeetingRunning');
+  $request = BIGBLUEBUTTON_BASE_URL . BIGBLUEBUTTON_IS_MEETING_RUNNING_URL . '?' . $query_string;
+  $xml = @simplexml_load_file($request);
+  $response = bbb_api_parse_response($xml);
+
+  if ($response->returncode == 'SUCCESS') {
+    return drupal_strtoupper($response->running) == 'TRUE' ? TRUE : FALSE;
+  }
+  else {
+    watchdog('bigbluebutton', '%message', array('%message' => $response->message), WATCHDOG_ERROR);
+    return FALSE;
+  }
+}
+
+/**
+* End Meeting (endMeeting)
+*
+* Use this to forcibly end a meeting and kick all participants out of the
+* meeting.
+*
+* @param ARRAY $params
+*   Associative array of additional url parameters. Components:
+*   - meetingToken: STRING The internal meeting token assigned by the API for
+*     this meeting when it was created. Note that either the meetingToken or
+*     the meetingID along with one of the passwords must be passed into this
+*     call in order to determine which meeting to find.
+*   - meetingID: STRING If you specified a meeting ID when calling create,
+*     then you can use either the generated meeting token or your specified
+*     meeting ID to find meetings. This parameter takes your meeting ID.
+*   - password: STRING The moderator password for this meeting. You can not
+*     end a meeting using the attendee password.
+*  @return BOOLEAN
+*    A string of either “true” or “false” that signals whether the meeting was
+*    successfully ended.
+*/
+// TODO: this call is not yet implemented.
+function bbb_api_endMeeting($params) {
+  $query_string = bbb_api_generate_querystring($params, 'endMeeting');
+  $request = BIGBLUEBUTTON_BASE_URL . BIGBLUEBUTTON_END_MEETING_URL . '?' . $query_string;
+  $xml = @simplexml_load_file($request);
+  $response = bbb_api_parse_response($xml);
+
+  if ($response->returncode == 'SUCCESS') {
+    unset($response->returncode);
+    return $response;
+  }
+  else {
+    watchdog('bigbluebutton', '%message', array('%message' => $response->message), WATCHDOG_ERROR);
+    return FALSE;
+  }
+}
+
+/**
+* Get Meeting Info (getMeetingInfo)
+*
+* This call will return all of a meeting's information, including the list of
+* attendees as well as start and end times.
+*
+* @param ARRY $params
+*   Associative array of additional url parameters. Components:
+*   - meetingToken: STRING The internal meeting token assigned by the API for
+*     this meeting when it was created. Note that either the meetingToken or
+*     the meetingID along with one of the passwords must be passed into this
+*     call in order to determine which meeting to find.
+*   - meetingID: STRING If you specified a meeting ID when calling create,
+*     then you can use either the generated meeting token or your specified
+*     meeting ID to find meetings. This parameter takes your meeting ID.
+*   - password: STRING (REQUIRED) The moderator password for this meeting. You
+*     can not get the meeting information using the attendee password.
+* @return OBJECT or FALSE
+*/
+// TODO: this call is not yet implemented.
+function bbb_api_getMeetingInfo($params) {
+  $query_string = bbb_api_generate_querystring($params, 'getMeetingInfo');
+  $request = BIGBLUEBUTTON_BASE_URL . BIGBLUEBUTTON_GET_MEETING_INFO_URL . '?' . $query_string;
+  $xml = @simplexml_load_file($request);
+  $response = bbb_api_parse_response($xml);
+
+  if ($response->returncode == 'SUCCESS') {
+    unset($response->returncode);
+    return $response;
+  }
+  else {
+    watchdog('bigbluebutton', '%message', array('%message' => $response->message), WATCHDOG_ERROR);
+    return FALSE;
+  }
+}
+
+/* Helper functions */
+
+/**
+* Generate a signed query string
+*/
+function bbb_api_generate_querystring($params = array(), $call = '') {
+  $query = array();
+  // URL encoding the parameters
+  foreach ($params as $key => $value) {
+    $query[] = $key . '=' . drupal_encode_path(trim($value));
+  }
+  // Putting it together
+  $query_string = implode('&', $query);
+  // Adding the checksum to query string and return
+  $query_string = $query_string . '&checksum=' . sha1($call . $query_string . BIGBLUEBUTTON_SECURITY_SALT);
+  return $query_string;
+}
+
+/**
+* Parse xml response
+*
+* @param XML
+* @return OBJECT
+*/
+function bbb_api_parse_response($xml) {
+  //TODO: Refactor
+  $response = new StdClass;
+  if ($xml) {
+    foreach ($xml as $element => $node) {
+      $response->$element = (string) $node;
+    }
+  }
+  return $response;
+}
+?>
diff --git a/includes/bbb_views.views.inc b/includes/bbb_views.views.inc
new file mode 100644
index 0000000..86dca70
--- /dev/null
+++ b/includes/bbb_views.views.inc
@@ -0,0 +1,201 @@
+<?php
+// $Id: bbb_views.views.inc,v 1.1.2.1 2010/03/15 16:55:31 sanduhrs Exp $
+
+/**
+ * @file
+ * BigBlueButton - Enables universities and colleges to deliver a high-quality
+ * learning experience.
+ *
+ * @author
+ * Stefan Auditor <stefan.auditor@erdfisch.de>
+ */
+
+/**
+ * Implement hook_views_handlers().
+ */
+function bbb_views_views_handlers() {
+  return array(
+    'info' => array(
+      'path' => drupal_get_path('module', 'bbb_views') . '/includes',
+    ),
+    'handlers' => array(
+      'views_handler_field_bbb_join_attendee' => array(
+        'parent' => 'views_handler_field',
+      ),
+      'views_handler_field_bbb_join_moderator' => array(
+        'parent' => 'views_handler_field',
+      ),
+    ),
+  );
+}
+
+/**
+ * Implement hook_views_data().
+ */
+function bbb_views_views_data() {
+  // Group
+  $data['bbb_meetings']['table']['group'] = t('Big Blue Button');
+  // Joins
+  $data['bbb_meetings']['table']['join']['node'] = array(
+    'left_field' => 'nid',
+    'field' => 'nid',
+    'type' => 'INNER'
+  );
+  // Mappings
+  $data['bbb_meetings']['meetingToken'] = array(
+    'title' => t('Meeting Token'),
+    'help' => t('The unique meeting token.'),
+    'field' => array(
+        'handler' => 'views_handler_field',
+    ),
+    'filter' => array(
+        'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+        'handler' => 'views_handler_sort',
+    ),
+  );
+  $data['bbb_meetings']['name'] = array(
+    'title' => t('Username'),
+    'help' => t('The username displayed in the meeting.'),
+    'field' => array(
+        'handler' => 'views_handler_field',
+    ),
+    'filter' => array(
+        'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+        'handler' => 'views_handler_sort',
+    ),
+  );
+  $data['bbb_meetings']['meetingID'] = array(
+    'title' => t('Meeting ID'),
+    'help' => t('The unique meeting ID.'),
+    'field' => array(
+        'handler' => 'views_handler_field',
+    ),
+    'filter' => array(
+        'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+        'handler' => 'views_handler_sort',
+    ),
+  );
+  $data['bbb_meetings']['attendeePW'] = array(
+    'title' => t('Attendee password'),
+    'help' => t('The password needed to join a meeting.'),
+    'field' => array(
+        'handler' => 'views_handler_field',
+    ),
+  );
+  $data['bbb_meetings']['moderatorPW'] = array(
+    'title' => t('Moderator password'),
+    'help' => t('The password needed to moderate a meeting.'),
+    'field' => array(
+        'handler' => 'views_handler_field',
+    ),
+  );
+  $data['bbb_meetings']['welcome'] = array(
+    'title' => t('Welcome message'),
+    'help' => t('The message displayed when joining a meeting.'),
+    'field' => array(
+        'handler' => 'views_handler_field',
+    ),
+  );
+  $data['bbb_meetings']['dialNumber'] = array(
+    'title' => t('Dial number'),
+    'help' => t('The number to dial to join the meeting by phone.'),
+    'field' => array(
+        'handler' => 'views_handler_field',
+    ),
+  );
+  $data['bbb_meetings']['logoutURL'] = array(
+    'title' => t('Logout URL'),
+    'help' => t('The URL the user gets redirected to when leaving the meeting.'),
+    'field' => array(
+        'handler' => 'views_handler_field_url',
+    ),
+  );
+  $data['bbb_meetings']['created'] = array(
+    'title' => t('Created'),
+    'help' => t('The creation timestamp.'),
+    'field' => array(
+        'handler' => 'views_handler_field_date',
+    ),
+    'filter' => array(
+        'handler' => 'views_handler_filter_date',
+    ),
+    'sort' => array(
+        'handler' => 'views_handler_sort_date',
+    ),
+  );
+  $data['bbb_meetings']['join_attendee'] = array(
+    'field' => array(
+      'title' => t('Join'),
+      'help' => t('Provide a simple link to join as attendee.'),
+      'handler' => 'views_handler_field_bbb_join_attendee',
+      'notafield' => TRUE,
+    ),
+  );
+  $data['bbb_meetings']['join_moderator'] = array(
+    'field' => array(
+      'title' => t('Join moderator'),
+      'help' => t('Provide a simple link to join as moderator.'),
+      'handler' => 'views_handler_field_bbb_join_moderator',
+      'notafield' => TRUE,
+    ),
+  );
+
+  // Group
+  $data['bbb_stats']['table']['group'] = t('Big Blue Button Stats');
+  // Joins
+  $data['bbb_stats']['table']['join']['node'] = array(
+    'left_field' => 'nid',
+    'field' => 'nid',
+    'type' => 'INNER'
+  );
+  $data['bbb_stats']['nid'] = array(
+    'title' => t('Node'),
+    'help' => t('Relation to the node table'),
+    'relationship' => array(
+        'base' => 'node',
+        'field' => 'nid',
+        'handler' => 'views_handler_relationship',
+        'label' => t('Node'),
+    ),
+  );
+  $data['bbb_stats']['table']['join']['users'] = array(
+    'left_field' => 'uid',
+    'field' => 'uid',
+    'type' => 'INNER'
+  );
+  // Mappings
+  $data['bbb_stats']['role'] = array(
+    'title' => t('Role'),
+    'help' => t("The user's role in the meeting."),
+    'field' => array(
+        'handler' => 'views_handler_field',
+    ),
+    'filter' => array(
+        'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+        'handler' => 'views_handler_sort',
+    ),
+  );
+  $data['bbb_stats']['joined'] = array(
+    'title' => t('Joined'),
+    'help' => t('The timestamp a user joined the meeting.'),
+    'field' => array(
+        'handler' => 'views_handler_field_date',
+    ),
+    'filter' => array(
+        'handler' => 'views_handler_filter_date',
+    ),
+    'sort' => array(
+        'handler' => 'views_handler_sort_date',
+    ),
+  );
+
+  return $data;
+}
diff --git a/includes/bbb_views.views_default.inc b/includes/bbb_views.views_default.inc
new file mode 100644
index 0000000..8d89aed
--- /dev/null
+++ b/includes/bbb_views.views_default.inc
@@ -0,0 +1,201 @@
+<?php
+// $Id: bbb_views.views_default.inc,v 1.1.2.1 2010/03/15 16:55:31 sanduhrs Exp $
+
+/**
+ * @file
+ * BigBlueButton - Enables universities and colleges to deliver a high-quality
+ * learning experience.
+ *
+ * @author
+ * Stefan Auditor <stefan.auditor@erdfisch.de>
+ */
+
+/**
+ * Implementation of hook_views_default_views().
+ */
+function bbb_views_views_default_views() {
+  $view = new view;
+  $view->name = 'meetings';
+  $view->description = '';
+  $view->tag = 'Big Blue Button';
+  $view->view_php = '';
+  $view->base_table = 'node';
+  $view->is_cacheable = FALSE;
+  $view->api_version = 2;
+  $view->disabled = TRUE; /* Edit this to true to make a default view disabled initially */
+  $handler = $view->new_display('default', 'Defaults', 'default');
+  $handler->override_option('fields', array(
+    'title' => array(
+      'label' => 'Title',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'strip_tags' => 0,
+        'html' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'link_to_node' => 0,
+      'exclude' => 0,
+      'id' => 'title',
+      'table' => 'node',
+      'field' => 'title',
+      'relationship' => 'none',
+    ),
+    'dialNumber' => array(
+      'label' => 'Dial number',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'strip_tags' => 0,
+        'html' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'exclude' => 0,
+      'id' => 'dialNumber',
+      'table' => 'bbb_meetings',
+      'field' => 'dialNumber',
+      'relationship' => 'none',
+    ),
+    'join_attendee' => array(
+      'id' => 'join_attendee',
+      'table' => 'bbb_meetings',
+      'field' => 'join_attendee',
+    ),
+    'view_node' => array(
+      'label' => 'Link',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'strip_tags' => 0,
+        'html' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'text' => '',
+      'exclude' => 0,
+      'id' => 'view_node',
+      'table' => 'node',
+      'field' => 'view_node',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('sorts', array(
+    'status' => array(
+      'order' => 'DESC',
+      'id' => 'status',
+      'table' => 'node',
+      'field' => 'status',
+      'override' => array(
+        'button' => 'Override',
+      ),
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('filters', array(
+    'status' => array(
+      'operator' => '=',
+      'value' => '1',
+      'group' => '0',
+      'exposed' => FALSE,
+      'expose' => array(
+        'operator' => FALSE,
+        'label' => '',
+      ),
+      'id' => 'status',
+      'table' => 'node',
+      'field' => 'status',
+      'override' => array(
+        'button' => 'Override',
+      ),
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('access', array(
+    'type' => 'none',
+  ));
+  $handler->override_option('cache', array(
+    'type' => 'none',
+  ));
+  $handler->override_option('title', 'Meetings');
+  $handler->override_option('style_plugin', 'table');
+  $handler->override_option('style_options', array(
+    'grouping' => '',
+    'override' => 1,
+    'sticky' => 0,
+    'order' => 'asc',
+    'columns' => array(
+      'title' => 'title',
+      'dialNumber' => 'dialNumber',
+      'view_node' => 'view_node',
+    ),
+    'info' => array(
+      'title' => array(
+        'sortable' => 0,
+        'separator' => '',
+      ),
+      'dialNumber' => array(
+        'separator' => '',
+      ),
+      'view_node' => array(
+        'separator' => '',
+      ),
+    ),
+    'default' => '-1',
+  ));
+  $handler = $view->new_display('page', 'Meetings', 'page_1');
+  $handler->override_option('path', 'meetings');
+  $handler->override_option('menu', array(
+    'type' => 'normal',
+    'title' => 'Meetings',
+    'description' => 'Meetings',
+    'weight' => '0',
+    'name' => 'navigation',
+  ));
+  $handler->override_option('tab_options', array(
+    'type' => 'none',
+    'title' => '',
+    'description' => '',
+    'weight' => 0,
+  ));
+}
diff --git a/includes/pages.bbb.inc b/includes/pages.bbb.inc
new file mode 100644
index 0000000..2be5573
--- /dev/null
+++ b/includes/pages.bbb.inc
@@ -0,0 +1,118 @@
+<?php
+// $Id: pages.bbb.inc,v 1.1.2.1 2010/03/15 16:55:31 sanduhrs Exp $
+
+/**
+ * @file
+ * BigBlueButton - Enables universities and colleges to deliver a high-quality
+ * learning experience.
+ *
+ * @author
+ * Stefan Auditor <stefan.auditor@erdfisch.de>
+ */
+
+/**
+ * Administrative settings; Menu callback
+ * TODO: Per node type settings?
+ */
+function bbb_settings() {
+
+  $form = array();
+  $form['bbb_server'] = array(
+    '#title' => 'Server settings',
+    '#type' => 'fieldset',
+    '#description' => t('Adjust the default server settings. Read more about BigBlueButton on !home. See the documentation for !documentation', array('!home' => l(t('BigBlueButton.org'), 'http://bigbluebutton.org/'), '!documentation' => l(t('installation instructions'), 'http://code.google.com/p/bigbluebutton/'))),
+  );
+  $form['bbb_server']['bbb_base_url'] = array(
+    '#title' => t('Base URL'),
+    '#type' => 'textfield',
+    '#default_value' => variable_get('bbb_base_url', BIGBLUEBUTTON_BASE_URL),
+    '#description' => t('The URL that points to your instance of BigBlueButton.'),
+  );
+  $form['bbb_server']['bbb_security_salt'] = array(
+    '#title' => t('Security Salt'),
+    '#type' => 'textfield',
+    '#default_value' => variable_get('bbb_security_salt', BIGBLUEBUTTON_SECURITY_SALT),
+    '#description' => t('The predefinde security salt. This is a server side configuration option check the BigBlueButton !documentation', array('!documentation' => l(t('documentation'), 'http://code.google.com/p/bigbluebutton/'))),
+  );
+  $form['bbb_client'] = array(
+    '#title' => t('Client settings'),
+    '#type' => 'fieldset',
+  );
+  $form['bbb_client']['bbb_display_mode'] = array(
+    '#title' => t('Display mode'),
+    '#type' => 'radios',
+    '#options' => array(
+      'inline' => t('Display inline'),
+      'blank' => t('Display in a new window'),
+    ),
+    '#default_value' => variable_get('bbb_display_mode', BIGBLUEBUTTON_DISPLAY_MODE),
+    '#description' => t('Choose wether to display the conference inline or in a new window.'),
+  );
+  $form['bbb_client']['bbb_display_height'] = array(
+    '#title' => t('Height x Width'),
+    '#type' => 'textfield',
+    '#default_value' => variable_get('bbb_display_height', BIGBLUEBUTTON_DISPLAY_HEIGHT),
+    '#prefix' => '<div class="container-inline">',
+    '#suffix' => 'x',
+    '#size' => 4,
+  );
+  $form['bbb_client']['bbb_display_width'] = array(
+    '#type' => 'textfield',
+    '#default_value' => variable_get('bbb_display_width', BIGBLUEBUTTON_DISPLAY_WIDTH),
+    '#suffix' => '</div>',
+    '#size' => 4,
+    '#description' => '<br />' . t('Give dimensions for inline display, e.g. <em>520px</em> x <em>100%</em>.'),
+  );
+//  $form['bbb_default'] = array(
+//    '#title' => 'Default settings',
+//    '#type' => 'fieldset',
+//    '#description' => t('You may provide default settings for nodes associated with BigBlueButton.'),
+//  );
+//  $form['bbb_default']['bbb_default_welcome'] = array(
+//    '#title' => t('Welcome message'),
+//    '#type' => 'textfield',
+//    '#default_value' => variable_get('bbb_default_welcome', ''),
+//    '#description' => t('A welcome message that gets displayed on the chat window when the participant joins. You can include keywords (%%CONFNAME%%, %%DIALNUM%%, %%CONFNUM%%) which will be substituted automatically.'),
+//  );
+//  $form['bbb_default']['bbb_default_dialNumber'] = array(
+//    '#title' => t('Dial number'),
+//    '#type' => 'textfield',
+//    '#default_value' => variable_get('bbb_default_dialNumber', ''),
+//    '#description' => t('The dial access number that participants can call in using regular phone.'),
+//  );
+//  $form['bbb_default']['bbb_default_dialNumber'] = array(
+//    '#title' => t('Dial number'),
+//    '#type' => 'textfield',
+//    '#default_value' => variable_get('bbb_default_dialNumber', ''),
+//    '#description' => t('The dial access number that participants can call in using regular phone.'),
+//  );
+//  $form['bbb_default']['bbb_default_logoutURL'] = array(
+//    '#title' => t('Logout URL'),
+//    '#type' => 'textfield',
+//    '#default_value' => variable_get('bbb_default_logoutURL', ''),
+//    '#description' => t('The dial access number that participants can call in using regular phone.'),
+//  );
+  $form['connection'] = array(
+    '#type' => 'submit',
+    '#executes_submit_callback' => FALSE,
+    '#value' => t('Test Connection'),
+  );
+    if (bbb_test_connection($form['bbb_server']['bbb_base_url']['#default_value'])) {
+      drupal_set_message(t('The connection has been established succesfully. Please save your settings now.'));
+    }
+    else {
+      drupal_set_message(t('The connection could not be established. Please adjust your settings.'), 'error');
+    }
+  return system_settings_form($form);
+}
+
+/**
+ * Test conection to Big Blue Button
+ */
+function bbb_test_connection($url) {
+  $response =  drupal_http_request($url, array(), 'GET', NULL, 3);
+  if ($response->redirect_code == 200 && $response->code == 302) {
+    return TRUE;
+  }
+  return FALSE;
+}
diff --git a/includes/views_handler_field_bbb_join_attendee.inc b/includes/views_handler_field_bbb_join_attendee.inc
new file mode 100644
index 0000000..7f6554a
--- /dev/null
+++ b/includes/views_handler_field_bbb_join_attendee.inc
@@ -0,0 +1,49 @@
+<?php
+// $Id: views_handler_field_bbb_join_attendee.inc,v 1.1.2.1 2010/03/15 16:55:31 sanduhrs Exp $
+
+/**
+ * @file
+ * BigBlueButton - Enables universities and colleges to deliver a high-quality
+ * learning experience.
+ *
+ * @author
+ * Stefan Auditor <stefan.auditor@erdfisch.de>
+ */
+
+/**
+ * Field handler to present a link to join a meeting as attendee.
+ */
+class views_handler_field_bbb_join_attendee extends views_handler_field {
+  function construct() {
+    parent::construct();
+    $this->additional_fields['nid'] = 'nid';
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['text'] = array('default' => '', 'translatable' => TRUE);
+
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['text'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Text to display'),
+      '#default_value' => $this->options['text'],
+    );
+  }
+
+  function query() {
+    $this->ensure_my_table();
+    $this->add_additional_fields();
+  }
+
+  function render($values) {
+    $text = !empty($this->options['text']) ? $this->options['text'] : t('view');
+    $nid = $values->{$this->aliases['nid']};
+    return l($text, "node/$nid/join/attendee");
+  }
+}
\ No newline at end of file
diff --git a/includes/views_handler_field_bbb_join_moderator.inc b/includes/views_handler_field_bbb_join_moderator.inc
new file mode 100644
index 0000000..09a7aee
--- /dev/null
+++ b/includes/views_handler_field_bbb_join_moderator.inc
@@ -0,0 +1,49 @@
+<?php
+// $Id: views_handler_field_bbb_join_moderator.inc,v 1.1.2.1 2010/03/15 16:55:31 sanduhrs Exp $
+
+/**
+ * @file
+ * BigBlueButton - Enables universities and colleges to deliver a high-quality
+ * learning experience.
+ *
+ * @author
+ * Stefan Auditor <stefan.auditor@erdfisch.de>
+ */
+
+/**
+ * Field handler to present a link to join a meeting as moderator.
+ */
+class views_handler_field_bbb_join_moderator extends views_handler_field {
+  function construct() {
+    parent::construct();
+    $this->additional_fields['nid'] = 'nid';
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['text'] = array('default' => '', 'translatable' => TRUE);
+
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['text'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Text to display'),
+      '#default_value' => $this->options['text'],
+    );
+  }
+
+  function query() {
+    $this->ensure_my_table();
+    $this->add_additional_fields();
+  }
+
+  function render($values) {
+    $text = !empty($this->options['text']) ? $this->options['text'] : t('view');
+    $nid = $values->{$this->aliases['nid']};
+    return l($text, "node/$nid/join/moderator");
+  }
+}
\ No newline at end of file
diff --git a/js/check_status.bbb.js b/js/check_status.bbb.js
new file mode 100644
index 0000000..f5f7cce
--- /dev/null
+++ b/js/check_status.bbb.js
@@ -0,0 +1,15 @@
+//$Id: check_status.bbb.js,v 1.1.2.1 2010/03/15 16:55:31 sanduhrs Exp $
+Drupal.behaviors.bbbCheckStatusInit = function () {
+  Drupal.bbbCheckStatus();
+  setInterval("Drupal.bbbCheckStatus();", 5000);
+}
+
+Drupal.bbbCheckStatus = function () {
+  var url = bbb_check_status_url;
+  $.getJSON(url, function(data) {
+    console.log(data);
+    if (data.is_running == true) {
+      location.href = location.href + '/meeting/attend';
+    }
+  });
+}
\ No newline at end of file
