aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/includes/ucp/ucp_groups.php
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB/includes/ucp/ucp_groups.php')
-rw-r--r--phpBB/includes/ucp/ucp_groups.php513
1 files changed, 512 insertions, 1 deletions
diff --git a/phpBB/includes/ucp/ucp_groups.php b/phpBB/includes/ucp/ucp_groups.php
index fce4dafe8a..96d9fca2e6 100644
--- a/phpBB/includes/ucp/ucp_groups.php
+++ b/phpBB/includes/ucp/ucp_groups.php
@@ -22,6 +22,7 @@ class ucp_groups
$return_page = '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $phpbb_root_path . "ucp.$phpEx$SID&amp;i=$id&amp;mode=$mode\">", '</a>');
+ $mark_ary = request_var('mark', array(0));
$submit = (!empty($_POST['submit'])) ? true : false;
$delete = (!empty($_POST['delete'])) ? true : false;
$error = $data = array();
@@ -365,7 +366,517 @@ class ucp_groups
break;
case 'manage':
- break;
+
+ $action = (isset($_POST['addusers'])) ? 'addusers' : request_var('action', '');
+ $group_id = request_var('g', 0);
+
+ if ($group_id)
+ {
+ $sql = 'SELECT *
+ FROM ' . GROUPS_TABLE . "
+ WHERE group_id = $group_id";
+ $result = $db->sql_query($sql);
+ $group_row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ if (!$group_row)
+ {
+ trigger_error($user->lang['NO_GROUP'] . $return_page);
+ }
+ }
+
+ switch ($action)
+ {
+ case 'edit':
+
+ if (!$group_id)
+ {
+ trigger_error($user->lang['NO_GROUP'] . $return_page);
+ }
+
+ if (!($row = group_memberships($group_id, $user->data['user_id'])) || !$row[0]['group_leader'])
+ {
+ trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page);
+ }
+
+ $file_uploads = (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on') ? true : false;
+ $user->add_lang(array('acp/groups', 'acp/common'));
+
+ $data = $submit_ary = array();
+
+ $update = (isset($_POST['update'])) ? true : false;
+
+ $error = array();
+
+ $avatar_select = basename(request_var('avatar_select', ''));
+ $category = basename(request_var('category', ''));
+
+ $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && is_writeable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false;
+
+ // Did we submit?
+ if ($update)
+ {
+ $group_name = request_var('group_name', '');
+ $group_description = request_var('group_description', '');
+ $group_type = request_var('group_type', GROUP_FREE);
+
+ $data['uploadurl'] = request_var('uploadurl', '');
+ $data['remotelink'] = request_var('remotelink', '');
+ $delete = request_var('delete', '');
+
+ $submit_ary = array(
+ 'colour' => request_var('group_colour', ''),
+ 'rank' => request_var('group_rank', 0),
+ 'receive_pm' => isset($_REQUEST['group_receive_pm']) ? 1 : 0,
+ 'message_limit' => request_var('group_message_limit', 0)
+ );
+
+ if (!empty($_FILES['uploadfile']['tmp_name']) || $data['uploadurl'] || $data['remotelink'])
+ {
+ $data['width'] = request_var('width', '');
+ $data['height'] = request_var('height', '');
+
+ // Avatar stuff
+ $var_ary = array(
+ 'uploadurl' => array('string', true, 5, 255),
+ 'remotelink' => array('string', true, 5, 255),
+ 'width' => array('string', true, 1, 3),
+ 'height' => array('string', true, 1, 3),
+ );
+
+ if (!($error = validate_data($data, $var_ary)))
+ {
+ $data['user_id'] = "g$group_id";
+
+ if ((!empty($_FILES['uploadfile']['tmp_name']) || $data['uploadurl']) && $can_upload)
+ {
+ list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_upload($data, $error);
+ }
+ else if ($data['remotelink'])
+ {
+ list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_remote($data, $error);
+ }
+ }
+ }
+ else if ($avatar_select && $config['allow_avatar_local'])
+ {
+ // check avatar gallery
+ if (is_dir($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category))
+ {
+ $submit_ary['avatar_type'] = AVATAR_GALLERY;
+
+ list($submit_ary['avatar_width'], $submit_ary['avatar_height']) = getimagesize($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category . '/' . $avatar_select);
+ $submit_ary['avatar'] = $category . '/' . $avatar_select;
+ }
+ }
+ else if ($delete)
+ {
+ $submit_ary['avatar'] = '';
+ $submit_ary['avatar_type'] = $submit_ary['avatar_width'] = $submit_ary['avatar_height'] = 0;
+ }
+
+ if ((isset($submit_ary['avatar']) && $submit_ary['avatar'] && (!isset($group_row['group_avatar']) || $group_row['group_avatar'] != $submit_ary['avatar'])) || $delete)
+ {
+ if (isset($group_row['group_avatar']) && $group_row['group_avatar'])
+ {
+ avatar_delete($group_row['group_avatar']);
+ }
+ }
+
+ // Only set the rank, colour, etc. if it's changed or if we're adding a new
+ // group. This prevents existing group members being updated if no changes
+ // were made.
+
+ $group_attributes = array();
+ $test_variables = array('rank', 'colour', 'avatar', 'avatar_type', 'avatar_width', 'avatar_height');
+ foreach ($test_variables as $test)
+ {
+ if ($action == 'add' || (isset($submit_ary[$test]) && $group_row['group_' . $test] != $submit_ary[$test]))
+ {
+ $group_attributes['group_' . $test] = $group_row['group_' . $test] = $submit_ary[$test];
+ }
+ }
+
+ if (!($error = group_create($group_id, $group_type, $group_name, $group_description, $group_attributes)))
+ {
+ $message = ($action == 'edit') ? 'GROUP_UPDATED' : 'GROUP_CREATED';
+ trigger_error($user->lang[$message] . $return_page);
+ }
+ }
+ else if (!$group_id)
+ {
+ $group_name = request_var('group_name', '');
+ $group_description = '';
+ $group_rank = 0;
+ $group_type = GROUP_OPEN;
+ }
+ else
+ {
+ $group_name = $group_row['group_name'];
+ $group_description = $group_row['group_description'];
+ $group_type = $group_row['group_type'];
+ $group_rank = $group_row['group_rank'];
+ }
+
+ $sql = 'SELECT *
+ FROM ' . RANKS_TABLE . '
+ WHERE rank_special = 1
+ ORDER BY rank_title';
+ $result = $db->sql_query($sql);
+
+ $rank_options = '<option value="0"' . ((!$group_rank) ? ' selected="selected"' : '') . '>' . $user->lang['USER_DEFAULT'] . '</option>';
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $selected = ($group_rank && $row['rank_id'] == $group_rank) ? ' selected="selected"' : '';
+ $rank_options .= '<option value="' . $row['rank_id'] . '"' . $selected . '>' . $row['rank_title'] . '</option>';
+ }
+ $db->sql_freeresult($result);
+
+ $type_free = ($group_type == GROUP_FREE) ? ' checked="checked"' : '';
+ $type_open = ($group_type == GROUP_OPEN) ? ' checked="checked"' : '';
+ $type_closed = ($group_type == GROUP_CLOSED) ? ' checked="checked"' : '';
+ $type_hidden = ($group_type == GROUP_HIDDEN) ? ' checked="checked"' : '';
+
+ if (isset($group_row['group_avatar']) && $group_row['group_avatar'])
+ {
+ switch ($group_row['group_avatar_type'])
+ {
+ case AVATAR_UPLOAD:
+ $avatar_img = $phpbb_root_path . $config['avatar_path'] . '/';
+ break;
+ case AVATAR_GALLERY:
+ $avatar_img = $phpbb_root_path . $config['avatar_gallery_path'] . '/';
+ break;
+ }
+ $avatar_img .= $group_row['group_avatar'];
+
+ $avatar_img = '<img src="' . $avatar_img . '" width="' . $group_row['group_avatar_width'] . '" height="' . $group_row['group_avatar_height'] . '" alt="" />';
+ }
+ else
+ {
+ $avatar_img = '<img src="' . $phpbb_root_path . 'adm/images/no_avatar.gif" alt="" />';
+ }
+
+ $display_gallery = (isset($_POST['display_gallery'])) ? true : false;
+
+ if ($config['allow_avatar_local'] && $display_gallery)
+ {
+ avatar_gallery($category, $avatar_select, 4);
+ }
+
+ $template->assign_vars(array(
+ 'S_EDIT' => true,
+ 'S_INCLUDE_SWATCH' => true,
+ 'S_CAN_UPLOAD' => $can_upload,
+ 'S_ERROR' => (sizeof($error)) ? true : false,
+ 'S_SPECIAL_GROUP' => ($group_type == GROUP_SPECIAL) ? true : false,
+ 'S_DISPLAY_GALLERY' => ($config['allow_avatar_local'] && !$display_gallery) ? true : false,
+ 'S_IN_GALLERY' => ($config['allow_avatar_local'] && $display_gallery) ? true : false,
+
+ 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '',
+ 'GROUP_NAME' => ($group_type == GROUP_SPECIAL) ? $user->lang['G_' . $group_name] : $group_name,
+ 'GROUP_INTERNAL_NAME' => $group_name,
+ 'GROUP_DESCRIPTION' => $group_description,
+ 'GROUP_RECEIVE_PM' => (isset($group_row['group_receive_pm']) && $group_row['group_receive_pm']) ? ' checked="checked"' : '',
+ 'GROUP_MESSAGE_LIMIT' => (isset($group_row['group_message_limit'])) ? $group_row['group_message_limit'] : 0,
+ 'GROUP_COLOUR' => (isset($group_row['group_colour'])) ? $group_row['group_colour'] : '',
+
+ 'S_RANK_OPTIONS' => $rank_options,
+ 'AVATAR_IMAGE' => $avatar_img,
+ 'AVATAR_MAX_FILESIZE' => $config['avatar_filesize'],
+ 'GROUP_AVATAR_WIDTH' => (isset($group_row['group_avatar_width'])) ? $group_row['group_avatar_width'] : '',
+ 'GROUP_AVATAR_HEIGHT' => (isset($group_row['group_avatar_height'])) ? $group_row['group_avatar_height'] : '',
+
+ 'GROUP_TYPE_FREE' => GROUP_FREE,
+ 'GROUP_TYPE_OPEN' => GROUP_OPEN,
+ 'GROUP_TYPE_CLOSED' => GROUP_CLOSED,
+ 'GROUP_TYPE_HIDDEN' => GROUP_HIDDEN,
+ 'GROUP_TYPE_SPECIAL' => GROUP_SPECIAL,
+
+ 'GROUP_FREE' => $type_free,
+ 'GROUP_OPEN' => $type_open,
+ 'GROUP_CLOSED' => $type_closed,
+ 'GROUP_HIDDEN' => $type_hidden,
+
+ 'U_SWATCH' => "{$phpbb_root_path}adm/swatch.$phpEx$SID&form=settings&name=group_colour",
+ 'U_ACTION' => "ucp.$phpEx$SID&amp;i=$id&amp;mode=$mode&amp;action=$action&amp;g=$group_id",
+ 'L_AVATAR_EXPLAIN' => sprintf($user->lang['AVATAR_EXPLAIN'], $config['avatar_max_width'], $config['avatar_max_height'], round($config['avatar_filesize'] / 1024)))
+ );
+
+ break;
+
+ case 'list':
+
+ if (!$group_id)
+ {
+ trigger_error($user->lang['NO_GROUP'] . $return_page);
+ }
+
+ if (!($row = group_memberships($group_id, $user->data['user_id'])) || !$row[0]['group_leader'])
+ {
+ trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page);
+ }
+
+ $user->add_lang(array('acp/groups', 'acp/common'));
+
+ // Total number of group members (non-leaders)
+ $sql = 'SELECT COUNT(user_id) AS total_members
+ FROM ' . USER_GROUP_TABLE . "
+ WHERE group_id = $group_id
+ AND group_leader <> 1";
+ $result = $db->sql_query($sql);
+
+ $total_members = (int) $db->sql_fetchfield('total_members', 0, $result);
+ $db->sql_freeresult($result);
+
+ $start = request_var('start', 0);
+
+ // Grab the members
+ $sql = 'SELECT u.user_id, u.username, u.user_regdate, u.user_posts, u.group_id, ug.group_leader, ug.user_pending
+ FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . " ug
+ WHERE ug.group_id = $group_id
+ AND u.user_id = ug.user_id
+ AND ug.group_leader = 0
+ ORDER BY ug.group_leader DESC, ug.user_pending ASC, u.username";
+ $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start);
+
+ $pending = false;
+
+ while ($row = $db->sql_fetchrow($result))
+ {
+ if ($row['user_pending'] && !$pending)
+ {
+ $template->assign_block_vars('member', array(
+ 'S_PENDING' => true)
+ );
+
+ $pending = true;
+ }
+
+ $template->assign_block_vars('member', array(
+ 'USERNAME' => $row['username'],
+ 'U_USER_VIEW' => "memberlist.$phpEx$SID&amp;mode=viewprofile&amp;u={$row['user_id']}",
+ 'S_GROUP_DEFAULT' => ($row['group_id'] == $group_id) ? true : false,
+ 'JOINED' => ($row['user_regdate']) ? $user->format_date($row['user_regdate'], $user->lang['DATE_FORMAT']) : '-',
+ 'USER_POSTS' => $row['user_posts'],
+ 'USER_ID' => $row['user_id'])
+ );
+ }
+ $db->sql_freeresult($result);
+
+ $s_action_options = '';
+ $options = array('default' => 'DEFAULT', 'approve' => 'APPROVE', 'deleteusers' => 'DELETE');
+
+ foreach ($options as $option => $lang)
+ {
+ $s_action_options .= '<option value="' . $option . '">' . $user->lang['GROUP_' . $lang] . '</option>';
+ }
+
+ $template->assign_vars(array(
+ 'S_LIST' => true,
+ 'S_ACTION_OPTIONS' => $s_action_options,
+ 'S_ON_PAGE' => on_page($total_members, $config['topics_per_page'], $start),
+ 'PAGINATION' => generate_pagination("ucp.$phpEx$SID&amp;i=$id&amp;mode=$mode&amp;action=$action&amp;g=$group_id", $total_members, $config['topics_per_page'], $start, true),
+
+ 'U_ACTION' => "ucp.$phpEx$SID&amp;i=$id&amp;mode=$mode&amp;g=$group_id",
+ 'U_FIND_USERNAME' => "memberlist.$phpEx$SID&amp;mode=searchuser&amp;form=list&amp;field=usernames")
+ );
+
+ break;
+
+ case 'approve':
+
+ if (!$group_id)
+ {
+ trigger_error($user->lang['NO_GROUP'] . $return_page);
+ }
+
+ if (!($row = group_memberships($group_id, $user->data['user_id'])) || !$row[0]['group_leader'])
+ {
+ trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page);
+ }
+
+ $user->add_lang('acp/groups');
+
+ // Approve, demote or promote
+ group_user_attributes('approve', $group_id, $mark_ary, false, ($group_id) ? $group_row['group_name'] : false);
+
+ trigger_error($user->lang['USERS_APPROVED'] . $return_page);
+ break;
+
+ case 'default':
+
+ if (!$group_id)
+ {
+ trigger_error($user->lang['NO_GROUP'] . $return_page);
+ }
+
+ if (!($row = group_memberships($group_id, $user->data['user_id'])) || !$row[0]['group_leader'])
+ {
+ trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page);
+ }
+
+ if (confirm_box(true))
+ {
+ if (!sizeof($mark_ary))
+ {
+ $start = 0;
+
+ do
+ {
+ $sql = 'SELECT user_id
+ FROM ' . USER_GROUP_TABLE . "
+ WHERE group_id = $group_id
+ ORDER BY user_id";
+ $result = $db->sql_query_limit($sql, 200, $start);
+
+ $mark_ary = array();
+ if ($row = $db->sql_fetchrow($result))
+ {
+ do
+ {
+ $mark_ary[] = $row['user_id'];
+ }
+ while ($row = $db->sql_fetchrow($result));
+
+ group_user_attributes('default', $group_id, $mark_ary, false, $group_row['group_name'], $group_row);
+
+ $start = (sizeof($mark_ary) < 200) ? 0 : $start + 200;
+ }
+ else
+ {
+ $start = 0;
+ }
+ $db->sql_freeresult($result);
+ }
+ while ($start);
+ }
+ else
+ {
+ group_user_attributes('default', $group_id, $mark_ary, false, $group_row['group_name'], $group_row);
+ }
+
+ $user->add_lang('acp/groups');
+
+ trigger_error($user->lang['GROUP_DEFS_UPDATED'] . $return_page);
+ }
+ else
+ {
+
+ $user->add_lang('acp/common');
+
+ confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
+ 'mark' => $mark_ary,
+ 'g' => $group_id,
+ 'i' => $id,
+ 'mode' => $mode,
+ 'action' => $action))
+ );
+ }
+
+ break;
+
+ case 'deleteusers':
+
+ $user->add_lang(array('acp/groups', 'acp/common'));
+
+ if (!($row = group_memberships($group_id, $user->data['user_id'])) || !$row[0]['group_leader'])
+ {
+ trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page);
+ }
+
+ if (confirm_box(true))
+ {
+ if (!$group_id)
+ {
+ trigger_error($user->lang['NO_GROUP'] . $return_page);
+ }
+
+ $error = group_user_del($group_id, $mark_ary, false, $group_row['group_name']);
+
+ if ($error)
+ {
+ trigger_error($user->lang[$error] . $return_page);
+ }
+
+ trigger_error($user->lang['GROUP_USERS_REMOVE'] . $return_page);
+ }
+ else
+ {
+ confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
+ 'mark' => $mark_ary,
+ 'g' => $group_id,
+ 'i' => $id,
+ 'mode' => $mode,
+ 'action' => $action))
+ );
+ }
+ break;
+
+ case 'addusers':
+
+ $user->add_lang(array('acp/groups', 'acp/common'));
+
+ $name_ary = request_var('usernames', '');
+
+ if (!$group_id)
+ {
+ trigger_error($user->lang['NO_GROUP'] . $return_page);
+ }
+
+ if (!$name_ary)
+ {
+ trigger_error($user->lang['NO_USERS'] . $return_page);
+ }
+
+ if (!($row = group_memberships($group_id, $user->data['user_id'])) || !$row[0]['group_leader'])
+ {
+ trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page);
+ }
+
+ $name_ary = array_unique(explode("\n", $name_ary));
+
+ $default = request_var('default', 0);
+
+ // Add user/s to group
+ if ($error = group_user_add($group_id, false, $name_ary, $group_row['group_name'], $default, 0, 0, $group_row))
+ {
+ trigger_error($user->lang[$error] . $return_page);
+ }
+
+ trigger_error($user->lang['GROUP_USERS_ADDED'] . $return_page);
+ break;
+
+ default:
+ $user->add_lang('acp/common');
+
+ $sql = 'SELECT g.group_id, g.group_name, g.group_description, g.group_type, ug.group_leader
+ FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
+ WHERE ug.user_id = ' . $user->data['user_id'] . '
+ AND g.group_id = ug.group_id
+ AND ug.group_leader = 1
+ ORDER BY g.group_type DESC, g.group_name';
+ $result = $db->sql_query($sql);
+
+ while ($value = $db->sql_fetchrow($result))
+ {
+ $template->assign_block_vars('leader', array(
+ 'GROUP_NAME' => ($value['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $value['group_name']] : $value['group_name'],
+ 'GROUP_DESC' => $value['group_description'],
+ 'GROUP_TYPE' => $value['group_type'],
+ 'GROUP_ID' => $value['group_id'],
+
+ 'U_LIST' => "{$phpbb_root_path}ucp.$phpEx$SID&amp;i=$id&amp;mode=$mode&amp;action=list&amp;g={$value['group_id']}",
+ 'U_EDIT' => "{$phpbb_root_path}ucp.$phpEx$SID&amp;i=$id&amp;mode=$mode&amp;action=edit&amp;g={$value['group_id']}")
+ );
+ }
+
+ $db->sql_freeresult($result);
+
+ break;
+ }
+
+ break;
}
$this->tpl_name = 'ucp_groups_' . $mode;
>935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
/*
 * Guillaume Cottenceau (gc@mandriva.com)
 *
 * Copyright 2000 Mandriva
 *
 * This software may be freely redistributed under the terms of the GNU
 * public license.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

/*
 * Portions from Erik Troan (ewt@redhat.com)
 *
 * Copyright 1996 Red Hat Software 
 *
 */


/*
 * This contains stuff related to probing:
 * (1) any (actually only SCSI, NET, CPQ, USB Controllers) devices (autoprobe for PCI and USB)
 * (2) IDE media
 * (3) SCSI media
 * (4) ETH devices
 */


#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <sys/socket.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <pci/pci.h>
#include <libldetect.h>
#include "stage1.h"

#include "log.h"
#include "utils.h"
#include "frontend.h"
#include "modules.h"
#include "pci-resource/pci-ids.h"
#ifdef ENABLE_USB
#include "usb-resource/usb-ids.h"
#endif
#ifdef ENABLE_PCMCIA
#include "sysfs/libsysfs.h"
#include "pcmcia-resource/pcmcia-ids.h"
#endif

#include "probing.h"


struct media_info {
	char * name;
	char * model;
	enum media_type type;
};


static void warning_insmod_failed(enum insmod_return r)
{
	if (IS_AUTOMATIC && r == INSMOD_FAILED_FILE_NOT_FOUND)
		return;
	if (r != INSMOD_OK) {
		if (r == INSMOD_FAILED_FILE_NOT_FOUND)
			stg1_error_message("This floppy doesn't contain the driver.");
		else
			stg1_error_message("Warning, installation of driver failed. (please include msg from <Alt-F3> for bugreports)");
	}
}

#ifndef DISABLE_NETWORK
struct net_description_elem
{
	char * intf_name;
	char * intf_description;
};
static struct net_description_elem net_descriptions[50];
static int net_descr_number = 0;
static char * intf_descr_for_discover = NULL;
static char * net_intf_too_early_name[50]; /* for modules providing more than one net intf */
static int net_intf_too_early_number = 0;
static int net_intf_too_early_ptr = 0;

const char * safe_descr(const char * text) {
	return text ? text : "unknown";
}

void prepare_intf_descr(const char * intf_descr)
{
	intf_descr_for_discover = strdup(intf_descr);
}

void net_discovered_interface(char * intf_name)
{
	if (!intf_descr_for_discover) {
		net_intf_too_early_name[net_intf_too_early_number++] = strdup(intf_name);
		return;
	}
	if (!intf_name) {
		if (net_intf_too_early_ptr >= net_intf_too_early_number) {
			log_message("NET: was expecting another network interface (broken net module?)");
			return;
		}
		net_descriptions[net_descr_number].intf_name = net_intf_too_early_name[net_intf_too_early_ptr++];
	}
	else
		net_descriptions[net_descr_number].intf_name = strdup(intf_name);
	net_descriptions[net_descr_number].intf_description = strdup(intf_descr_for_discover);
	intf_descr_for_discover = NULL;
	net_descr_number++;
}

char * get_net_intf_description(char * intf_name)
{
	int i;
	for (i = 0; i < net_descr_number ; i++)
		if (!strcmp(net_descriptions[i].intf_name, intf_name))
			return net_descriptions[i].intf_description;
	return strdup("unknown");
}
#endif

static int device_match_modules_list(struct pciusb_entry *e, char **modules, unsigned int modules_len) {
	int i;
	if (!e->module)
		return 0;
	for (i = 0; i < modules_len; i++)
		if (!strcmp(modules[i], e->module))
			return 1;
	return 0;
}

struct pcitable_entry *detected_devices = NULL;
int detected_devices_len = 0;

static void detected_devices_destroy(void)
{
	if (detected_devices)
		free(detected_devices);
}

static struct pcitable_entry *detected_device_new(void)
{
	static int detected_devices_maxlen = 0;
	if (detected_devices_len >= detected_devices_maxlen) {
		detected_devices_maxlen += 32;
		if (detected_devices == NULL)
 			detected_devices = malloc(detected_devices_maxlen * sizeof(*detected_devices));
		else
			detected_devices = realloc(detected_devices, detected_devices_maxlen * sizeof(*detected_devices));
		if (detected_devices == NULL)
			log_perror("detected_device_new: could not (re)allocate table. Let it crash, sorry");
	}
	return &detected_devices[detected_devices_len++];
}

/* FIXME: factorize with probe_that_type() */

static void add_detected_device(unsigned short vendor, unsigned short device, unsigned int subvendor, unsigned int subdevice, const char *name, const char *module)
{
	struct pcitable_entry *dev = detected_device_new();
	dev->vendor = vendor;
	dev->device = device;
	dev->subvendor = subvendor;
	dev->subdevice = subdevice;
	strncpy(dev->module, module, sizeof(dev->module) - 1);
	dev->module[sizeof(dev->module) - 1] = '\0';
	strncpy(dev->description, safe_descr(name), sizeof(dev->description) - 1);
	dev->description[sizeof(dev->description) - 1] = '\0';
	log_message("detected device (%04x, %04x, %04x, %04x, %s, %s)", vendor, device, subvendor, subdevice, name, module);
}

static int add_detected_device_if_match(struct pciusb_entry *e, char **modules, unsigned int modules_len)
{
	int ret = device_match_modules_list(e, modules, modules_len);
	if (ret)
		add_detected_device(e->vendor, e->device, e->subvendor, e->subdevice,
				    e->text, e->module);
	return ret;
}

void probing_detect_devices()
{
        static int already_detected_devices = 0;
	struct pciusb_entries entries;
	int i;

	if (already_detected_devices)
		return;

	entries = pci_probe();
	for (i = 0; i < entries.nb; i++) {
		struct pciusb_entry *e = &entries.entries[i];
#ifndef DISABLE_PCIADAPTERS
#ifndef DISABLE_MEDIAS
		if (add_detected_device_if_match(e, medias_ide_pci_modules, medias_ide_pci_modules_len))
			continue;
		if (add_detected_device_if_match(e, medias_other_pci_modules, medias_other_pci_modules_len))
			continue;
#endif

#ifndef DISABLE_NETWORK
		if (add_detected_device_if_match(e, network_pci_modules, network_pci_modules_len))
			continue;
#endif

#ifdef ENABLE_USB
		if (add_detected_device_if_match(e, usb_controller_modules, usb_controller_modules_len))
			continue;
#endif
#endif
		/* device can't be found in built-in pcitables, but keep it */
		add_detected_device(e->vendor, e->device, e->subvendor, e->subdevice, e->text, e->module);
	}
	pciusb_free(&entries);

	already_detected_devices = 1;
}

void probing_destroy(void)
{
	detected_devices_destroy();
}

#ifndef DISABLE_MEDIAS
static const char * get_alternate_module(const char * name)
{
	struct alternate_mapping {
		const char * a;
		const char * b;
	};
	static struct alternate_mapping mappings[] = {
                { "ahci", "ata_piix" },
        };
	int mappings_nb = sizeof(mappings) / sizeof(struct alternate_mapping);
        int i;

	for (i=0; i<mappings_nb; i++) {
		const char * alternate = NULL;
		if (streq(name, mappings[i].a))
			alternate = mappings[i].b;
		else if (streq(name, mappings[i].b))
			alternate = mappings[i].a;
		if (alternate) {
			log_message("found alternate module %s for driver %s", alternate, name);
			return alternate;
		}
	}
        return NULL;
}
#endif

void discovered_device(enum driver_type type, const char * description, const char * driver)
{
	description = safe_descr(description);

	enum insmod_return failed = INSMOD_FAILED;
#ifndef DISABLE_MEDIAS
	if (type == MEDIA_ADAPTERS) {
		const char * alternate = NULL;
		wait_message("Loading driver for media adapter:\n \n%s", description);
		failed = my_insmod(driver, MEDIA_ADAPTERS, NULL, 1);
		alternate = get_alternate_module(driver);
		if (!IS_NOAUTO && alternate) {
			failed = failed || my_insmod(alternate, MEDIA_ADAPTERS, NULL, 1);
		}
		remove_wait_message();
		warning_insmod_failed(failed);
	}
#endif
#ifndef DISABLE_NETWORK
	if (type == NETWORK_DEVICES) {
		wait_message("Loading driver for network device:\n \n%s", description);
		prepare_intf_descr(description);
		failed = my_insmod(driver, NETWORK_DEVICES, NULL, 1);
		warning_insmod_failed(failed);
		remove_wait_message();
		if (intf_descr_for_discover) /* for modules providing more than one net intf */
			net_discovered_interface(NULL);
	}
#endif
#ifdef ENABLE_USB
	if (type == USB_CONTROLLERS)
                /* we can't allow additional modules floppy since we need usbhid for keystrokes of usb keyboards */
		failed = my_insmod(driver, USB_CONTROLLERS, NULL, 0);
#endif
}

void probe_pci_modules(enum driver_type type, char **pci_modules, unsigned int  pci_modules_len) {
	struct pciusb_entries entries;
	int i;

	entries = pci_probe();
	for (i = 0; i < entries.nb; i++) {
		struct pciusb_entry *e = &entries.entries[i];
		if (device_match_modules_list(e, pci_modules, pci_modules_len)) {
			log_message("PCI: device %04x %04x %04x %04x is \"%s\", driver is %s",
				    e->vendor, e->device, e->subvendor, e->subdevice, safe_descr(e->text), e->module);
			discovered_device(type, e->text, e->module);
		}
	}
	pciusb_free(&entries);
}

/** Loads modules for known virtio devices
 *
 * virtio modules are not being loaded using the PCI probing mechanism
 * because pcitable.gz does not have IDs for these devices.
 *
 * The possible correct solution for it is to fix the script which
 * generates pcitable.gz to handle the virtio_device_id structure.
 */
void probe_virtio_modules(void)
{
	struct pciusb_entries entries;
	int i;
	char *name;
	char *options;
	int loaded_pci = 0;

	entries = pci_probe();
	for (i = 0; i < entries.nb; i++) {
		struct pciusb_entry *e = &entries.entries[i];
		if (e->vendor == VIRTIO_PCI_VENDOR) {
			if (!loaded_pci) {
				log_message("loading virtio-pci");
				my_insmod("virtio_pci", ANY_DRIVER_TYPE, NULL, 0);
				loaded_pci = 1;
			}

			name = NULL;
			options = NULL;

			switch (e->subdevice) {
			case VIRTIO_ID_NET:
				name = "virtio_net";
				options = "csum=0";
				break;
			case VIRTIO_ID_BLOCK:
				name = "virtio_blk";
				break;
			case VIRTIO_ID_BALLOON:
				name = "virtio_balloon";
				break;
			default:
				log_message("warning: unknown virtio device %04x", e->device);
			}
			if (name) {
				log_message("virtio: loading %s", name);
				my_insmod(name, ANY_DRIVER_TYPE, options, 0);
			}
		}
	}
	pciusb_free(&entries);
}

#ifdef ENABLE_USB
void probe_that_type(enum driver_type type, enum media_bus bus)
#else
void probe_that_type(enum driver_type type, enum media_bus bus __attribute__ ((unused)))
#endif
{
        static int already_probed_usb_controllers = 0;
        static int already_loaded_usb_scsi = 0;
        static int already_probed_virtio_devices = 0;

	/* ---- PCI probe ---------------------------------------------- */
	if (bus != BUS_USB) {
		switch (type) {
#ifndef DISABLE_PCIADAPTERS
#ifndef DISABLE_MEDIAS
			static int already_probed_media_adapters = 0;
		case MEDIA_ADAPTERS:
			if (already_probed_media_adapters)
				break;
			already_probed_media_adapters = 1;
			probe_pci_modules(type, medias_ide_pci_modules, medias_ide_pci_modules_len);
			probe_pci_modules(type, medias_other_pci_modules, medias_other_pci_modules_len);
			break;
#endif
#ifndef DISABLE_NETWORK
		case NETWORK_DEVICES:
			probe_pci_modules(type, network_pci_modules, network_pci_modules_len);
			break;
#endif
#endif
#ifdef ENABLE_USB
		case USB_CONTROLLERS:
			if (already_probed_usb_controllers || IS_NOAUTO)
				break;
			already_probed_usb_controllers = 1;
			probe_pci_modules(type, usb_controller_modules, usb_controller_modules_len);
			break;
#endif
		case VIRTIO_DEVICES:
			if (already_probed_virtio_devices)
				break;
			probe_virtio_modules();
			already_probed_virtio_devices = 1;
			break;
		default:
			break;
		}
	}


#ifdef ENABLE_USB
	/* ---- USB probe ---------------------------------------------- */
	if ((bus == BUS_USB || bus == BUS_ANY) && !(IS_NOAUTO)) {
		static int already_mounted_usbdev = 0;
		struct pciusb_entries entries;
		int i;

		if (!already_probed_usb_controllers)
			probe_that_type(USB_CONTROLLERS, BUS_ANY);

		if (!already_mounted_usbdev) {
			already_mounted_usbdev = 1;
			if (mount("none", "/proc/bus/usb", "usbfs", 0, NULL) &&
			    mount("none", "/proc/bus/usb", "usbdevfs", 0, NULL)) {
				log_message("USB: couldn't mount /proc/bus/usb");
				goto end_usb_probe;
			}
			wait_message("Detecting USB devices.");
			sleep(4); /* sucking background work */
			my_insmod("usbhid", ANY_DRIVER_TYPE, NULL, 0);
			remove_wait_message();
		}

		if (type != NETWORK_DEVICES)
			goto end_usb_probe;

		entries = usb_probe();
		for (i = 0; i < entries.nb; i++) {
			struct pciusb_entry *e = &entries.entries[i];
			if (device_match_modules_list(e, usb_modules, usb_modules_len)) {
				log_message("USB: device %04x %04x is \"%s\" (%s)", e->vendor, e->device, safe_descr(e->text), e->module);
				discovered_device(type, e->text, e->module);
			}
		}
		pciusb_free(&entries);
	end_usb_probe:;
	}
#endif

#ifdef ENABLE_PCMCIA
	/* ---- PCMCIA probe ---------------------------------------------- */
	if ((bus == BUS_PCMCIA || bus == BUS_ANY) && !(IS_NOAUTO)) {
		struct pcmcia_alias * pcmciadb = NULL;
		unsigned int len = 0;
		char *base = "/sys/bus/pcmcia/devices";
		DIR *dir;
		struct dirent *dent;

		dir = opendir(base);
		if (dir == NULL)
			goto end_pcmcia_probe;

		switch (type) {
#ifndef DISABLE_MEDIAS
		case MEDIA_ADAPTERS:
			pcmciadb = medias_pcmcia_ids;
			len      = medias_pcmcia_num_ids;
			break;
#endif
#ifndef DISABLE_NETWORK
		case NETWORK_DEVICES:
			pcmciadb = network_pcmcia_ids;
			len      = network_pcmcia_num_ids;
			break;
#endif
		default:
			goto end_pcmcia_probe;
                }

                for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
			struct sysfs_attribute *modalias_attr;
			char keyfile[256];
			int i, id;

			if (dent->d_name[0] == '.')
				continue;

			log_message("PCMCIA: device found %s", dent->d_name);

			snprintf(keyfile, sizeof(keyfile)-1, "%s/%s/modalias", base, dent->d_name);
			modalias_attr = sysfs_open_attribute(keyfile);
			if (!modalias_attr)
				continue;
			if (sysfs_read_attribute(modalias_attr) != 0 || !modalias_attr->value) {
				sysfs_close_attribute(modalias_attr);
				continue;
			}

			log_message("PCMCIA: device found %s", modalias_attr->value);

			for (i = 0; i < len; i++) {
				if (!fnmatch(pcmciadb[i].modalias, modalias_attr->value, 0)) {
					char product[256];

					log_message("PCMCIA: device found %s (%s)", pcmciadb[i].modalias, pcmciadb[i].module);
					strcpy(product, "");
					for (id = 1; id <= 4; id++) {
						struct sysfs_attribute *product_attr;
						snprintf(keyfile, sizeof(keyfile)-1, "%s/%s/prod_id%d", base, dent->d_name, id);
						product_attr = sysfs_open_attribute(keyfile);
						if (!product_attr)
							continue;
						if (sysfs_read_attribute(product_attr) || !product_attr->value) {
							sysfs_close_attribute(product_attr);
							continue;
						}
						snprintf(product + strlen(product), sizeof(product)-strlen(product)-1, "%s%s", product[0] ? " " : "", product_attr->value);
						if (product[strlen(product)-1] == '\n')
							product[strlen(product)-1] = '\0';
						sysfs_close_attribute(product_attr);
					}

					if (!product[0])
						strcpy(product, "PCMCIA device");

					log_message("PCMCIA: device found %s (%s)", product, pcmciadb[i].module);
					discovered_device(type, product, pcmciadb[i].module);
				}
			}

			sysfs_close_attribute(modalias_attr);
		}
	end_pcmcia_probe:;
		if (dir)
			closedir(dir);
	}
#endif

        /* be sure to load usb-storage after media adapters, so that they are in
           same order than reboot, so that naming is the same */